From c59b70841c36277464b51161e3fcf12dfcb667e0 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Fri, 7 Mar 2025 10:13:30 +0800 Subject: [PATCH 01/80] Emit warning while outputs is not exe and prints linkage info Signed-off-by: xizheyin --- compiler/rustc_codegen_ssa/src/back/link.rs | 19 +++++++++++++++++++ ...rning-print-link-info-without-staticlib.rs | 5 +++++ ...g-print-link-info-without-staticlib.stderr | 6 ++++++ ...t-warning-while-exe-and-print-link-info.rs | 3 +++ ...rning-while-exe-and-print-link-info.stderr | 4 ++++ tests/ui/print-request/stability.rs | 1 + 6 files changed, 38 insertions(+) create mode 100644 tests/ui/print-request/emit-warning-print-link-info-without-staticlib.rs create mode 100644 tests/ui/print-request/emit-warning-print-link-info-without-staticlib.stderr create mode 100644 tests/ui/print-request/emit-warning-while-exe-and-print-link-info.rs create mode 100644 tests/ui/print-request/emit-warning-while-exe-and-print-link-info.stderr diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 323538969d73..ffa888a17d0c 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -68,6 +68,23 @@ pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) { } } +fn check_link_info_print_request(sess: &Session, crate_type: CrateType) { + let print_native_static_libs = + sess.opts.prints.iter().any(|p| p.kind == PrintKind::NativeStaticLibs); + if print_native_static_libs { + if crate_type != CrateType::Staticlib { + sess.dcx() + .warn(format!("cannot output linkage information without staticlib crate-type")); + sess.dcx() + .note(format!("consider `--crate-type staticlib` to print linkage information")); + } else if !sess.opts.output_types.should_link() { + sess.dcx().warn(format!( + "skipping link step due to conflict: cannot output linkage information without emitting link" + )); + } + } +} + /// Performs the linkage portion of the compilation phase. This will generate all /// of the requested outputs for this compilation session. pub fn link_binary( @@ -178,6 +195,8 @@ pub fn link_binary( tempfiles_for_stdout_output.push(out_filename); } } + + check_link_info_print_request(sess, crate_type); } // Remove the temporary object file and metadata if we aren't saving temps. diff --git a/tests/ui/print-request/emit-warning-print-link-info-without-staticlib.rs b/tests/ui/print-request/emit-warning-print-link-info-without-staticlib.rs new file mode 100644 index 000000000000..b100c062bba4 --- /dev/null +++ b/tests/ui/print-request/emit-warning-print-link-info-without-staticlib.rs @@ -0,0 +1,5 @@ +//@ compile-flags: --print native-static-libs +//@ check-pass +//~? WARN cannot output linkage information without staticlib crate-type + +fn main() {} diff --git a/tests/ui/print-request/emit-warning-print-link-info-without-staticlib.stderr b/tests/ui/print-request/emit-warning-print-link-info-without-staticlib.stderr new file mode 100644 index 000000000000..ceff08baa13a --- /dev/null +++ b/tests/ui/print-request/emit-warning-print-link-info-without-staticlib.stderr @@ -0,0 +1,6 @@ +warning: cannot output linkage information without staticlib crate-type + +note: consider `--crate-type staticlib` to print linkage information + +warning: 1 warning emitted + diff --git a/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.rs b/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.rs new file mode 100644 index 000000000000..48f5475c8849 --- /dev/null +++ b/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.rs @@ -0,0 +1,3 @@ +//@ compile-flags: --print native-static-libs --crate-type staticlib --emit metadata +//@ check-pass +//~? WARN skipping link step due to conflict: cannot output linkage information without emitting link diff --git a/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.stderr b/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.stderr new file mode 100644 index 000000000000..0b46d2f68481 --- /dev/null +++ b/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.stderr @@ -0,0 +1,4 @@ +warning: skipping link step due to conflict: cannot output linkage information without emitting link + +warning: 1 warning emitted + diff --git a/tests/ui/print-request/stability.rs b/tests/ui/print-request/stability.rs index 54142ce78cef..fbcdf916cc7c 100644 --- a/tests/ui/print-request/stability.rs +++ b/tests/ui/print-request/stability.rs @@ -110,3 +110,4 @@ fn main() {} //[check_cfg]~? ERROR the `-Z unstable-options` flag must also be passed to enable the `check-cfg` print option //[supported_crate_types]~? ERROR the `-Z unstable-options` flag must also be passed to enable the `supported-crate-types` print option //[target_spec_json]~? ERROR the `-Z unstable-options` flag must also be passed to enable the `target-spec-json` print option +//[native_static_libs]~? WARNING cannot output linkage information without staticlib crate-type From 98bb597c05c32365abbd6898f278b097352774ed Mon Sep 17 00:00:00 2001 From: xizheyin Date: Fri, 2 May 2025 22:37:33 +0800 Subject: [PATCH 02/80] Update compiler/rustc_codegen_ssa/src/back/link.rs Co-authored-by: bjorn3 <17426603+bjorn3@users.noreply.github.com> --- compiler/rustc_codegen_ssa/src/back/link.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index ffa888a17d0c..28c7b5b27454 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -79,7 +79,7 @@ fn check_link_info_print_request(sess: &Session, crate_type: CrateType) { .note(format!("consider `--crate-type staticlib` to print linkage information")); } else if !sess.opts.output_types.should_link() { sess.dcx().warn(format!( - "skipping link step due to conflict: cannot output linkage information without emitting link" + "cannot output linkage information when --emit link is not passed" )); } } From 72a9219e82c157041bfc8dfd378c9cb2b09c0650 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Fri, 2 May 2025 22:56:27 +0800 Subject: [PATCH 03/80] check all crate-type to find staticlib Signed-off-by: xizheyin --- compiler/rustc_codegen_ssa/src/back/link.rs | 12 ++++++------ .../emit-warning-while-exe-and-print-link-info.rs | 2 +- ...emit-warning-while-exe-and-print-link-info.stderr | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 28c7b5b27454..1e9d9338b135 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -68,19 +68,19 @@ pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) { } } -fn check_link_info_print_request(sess: &Session, crate_type: CrateType) { +fn check_link_info_print_request(sess: &Session, crate_types: &[CrateType]) { let print_native_static_libs = sess.opts.prints.iter().any(|p| p.kind == PrintKind::NativeStaticLibs); + let has_staticlib = crate_types.iter().any(|ct| *ct == CrateType::Staticlib); if print_native_static_libs { - if crate_type != CrateType::Staticlib { + if !has_staticlib { sess.dcx() .warn(format!("cannot output linkage information without staticlib crate-type")); sess.dcx() .note(format!("consider `--crate-type staticlib` to print linkage information")); } else if !sess.opts.output_types.should_link() { - sess.dcx().warn(format!( - "cannot output linkage information when --emit link is not passed" - )); + sess.dcx() + .warn(format!("cannot output linkage information when --emit link is not passed")); } } } @@ -196,7 +196,7 @@ pub fn link_binary( } } - check_link_info_print_request(sess, crate_type); + check_link_info_print_request(sess, &codegen_results.crate_info.crate_types); } // Remove the temporary object file and metadata if we aren't saving temps. diff --git a/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.rs b/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.rs index 48f5475c8849..3e9ca457a9c9 100644 --- a/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.rs +++ b/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.rs @@ -1,3 +1,3 @@ //@ compile-flags: --print native-static-libs --crate-type staticlib --emit metadata //@ check-pass -//~? WARN skipping link step due to conflict: cannot output linkage information without emitting link +//~? WARN cannot output linkage information when --emit link is not passed diff --git a/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.stderr b/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.stderr index 0b46d2f68481..b32e1437d6b5 100644 --- a/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.stderr +++ b/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.stderr @@ -1,4 +1,4 @@ -warning: skipping link step due to conflict: cannot output linkage information without emitting link +warning: cannot output linkage information when --emit link is not passed warning: 1 warning emitted From f66787a08d57dc1296619b314d2be596085bfeef Mon Sep 17 00:00:00 2001 From: xizheyin Date: Fri, 2 May 2025 23:14:18 +0800 Subject: [PATCH 04/80] Update compiler/rustc_codegen_ssa/src/back/link.rs Co-authored-by: bjorn3 <17426603+bjorn3@users.noreply.github.com> Signed-off-by: xizheyin --- compiler/rustc_codegen_ssa/src/back/link.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 1e9d9338b135..62c389ec7915 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -195,10 +195,10 @@ pub fn link_binary( tempfiles_for_stdout_output.push(out_filename); } } - - check_link_info_print_request(sess, &codegen_results.crate_info.crate_types); } + check_link_info_print_request(sess, &codegen_results.crate_info.crate_types); + // Remove the temporary object file and metadata if we aren't saving temps. sess.time("link_binary_remove_temps", || { // If the user requests that temporaries are saved, don't delete any. From 06da7b31ac227edb12fbf9e3760d2fb42fe7084c Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Mon, 12 May 2025 23:08:54 +0800 Subject: [PATCH 05/80] fixes: ide-assists, generate_new indent loses --- .../ide-assists/src/handlers/generate_new.rs | 137 +++++++++++++++++- 1 file changed, 136 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs index f963f48d62ab..4837f92f9345 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs @@ -129,17 +129,23 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option // Get the mutable version of the impl to modify let impl_def = if let Some(impl_def) = impl_def { + fn_.indent(impl_def.indent_level()); builder.make_mut(impl_def) } else { // Generate a new impl to add the method to let impl_def = generate_impl(&ast::Adt::Struct(strukt.clone())); + let indent_level = strukt.indent_level(); + fn_.indent(indent_level); // Insert it after the adt let strukt = builder.make_mut(strukt.clone()); ted::insert_all_raw( ted::Position::after(strukt.syntax()), - vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()], + vec![ + make::tokens::whitespace(&format!("\n\n{indent_level}")).into(), + impl_def.syntax().clone().into(), + ], ); impl_def @@ -425,6 +431,135 @@ impl Foo { ); } + #[test] + fn non_zero_indent() { + check_assist( + generate_new, + r#" +mod foo { + struct $0Foo {} +} +"#, + r#" +mod foo { + struct Foo {} + + impl Foo { + fn $0new() -> Self { + Self { } + } + } +} +"#, + ); + check_assist( + generate_new, + r#" +mod foo { + mod bar { + struct $0Foo {} + } +} +"#, + r#" +mod foo { + mod bar { + struct Foo {} + + impl Foo { + fn $0new() -> Self { + Self { } + } + } + } +} +"#, + ); + check_assist( + generate_new, + r#" +mod foo { + struct $0Foo {} + + impl Foo { + fn some() {} + } +} +"#, + r#" +mod foo { + struct Foo {} + + impl Foo { + fn $0new() -> Self { + Self { } + } + + fn some() {} + } +} +"#, + ); + check_assist( + generate_new, + r#" +mod foo { + mod bar { + struct $0Foo {} + + impl Foo { + fn some() {} + } + } +} +"#, + r#" +mod foo { + mod bar { + struct Foo {} + + impl Foo { + fn $0new() -> Self { + Self { } + } + + fn some() {} + } + } +} +"#, + ); + check_assist( + generate_new, + r#" +mod foo { + mod bar { +struct $0Foo {} + + impl Foo { + fn some() {} + } + } +} +"#, + r#" +mod foo { + mod bar { +struct Foo {} + + impl Foo { + fn $0new() -> Self { + Self { } + } + + fn some() {} + } + } +} +"#, + ); + } + #[test] fn check_visibility_of_new_fn_based_on_struct() { check_assist( From 6a35b51860ecf1b9ecbbe6d02579dcd53291e006 Mon Sep 17 00:00:00 2001 From: A4-Tacks Date: Wed, 14 May 2025 23:02:32 +0800 Subject: [PATCH 06/80] fix: ide-assists, generate mut trait impl indent --- .../src/handlers/generate_mut_trait_impl.rs | 94 ++++++++++++++++++- 1 file changed, 91 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs index 2ac960ed7e18..bab2ccf3f337 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs @@ -1,7 +1,7 @@ use ide_db::famous_defs::FamousDefs; use syntax::{ AstNode, - ast::{self, make}, + ast::{self, edit_in_place::Indent, make}, ted, }; @@ -46,6 +46,7 @@ use crate::{AssistContext, AssistId, Assists}; // ``` pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let impl_def = ctx.find_node_at_offset::()?.clone_for_update(); + let indent = impl_def.indent_level(); let trait_ = impl_def.trait_()?; if let ast::Type::PathType(trait_path) = trait_ { @@ -97,8 +98,8 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_> })?; let assoc_list = make::assoc_item_list().clone_for_update(); - assoc_list.add_item(syntax::ast::AssocItem::Fn(fn_)); ted::replace(impl_def.assoc_item_list()?.syntax(), assoc_list.syntax()); + impl_def.get_or_create_assoc_item_list().add_item(syntax::ast::AssocItem::Fn(fn_)); let target = impl_def.syntax().text_range(); acc.add( @@ -106,7 +107,7 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_> "Generate `IndexMut` impl from this `Index` trait", target, |edit| { - edit.insert(target.start(), format!("$0{impl_def}\n\n")); + edit.insert(target.start(), format!("$0{impl_def}\n\n{indent}")); }, ) } @@ -189,6 +190,93 @@ impl core::ops::Index for [T; 3] where T: Copy { ); } + #[test] + fn test_generate_mut_trait_impl_non_zero_indent() { + check_assist( + generate_mut_trait_impl, + r#" +//- minicore: index +mod foo { + pub enum Axis { X = 0, Y = 1, Z = 2 } + + impl core::ops::Index$0 for [T; 3] where T: Copy { + type Output = T; + + fn index(&self, index: Axis) -> &Self::Output { + let var_name = &self[index as usize]; + var_name + } + } +} +"#, + r#" +mod foo { + pub enum Axis { X = 0, Y = 1, Z = 2 } + + $0impl core::ops::IndexMut for [T; 3] where T: Copy { + fn index_mut(&mut self, index: Axis) -> &mut Self::Output { + let var_name = &self[index as usize]; + var_name + } + } + + impl core::ops::Index for [T; 3] where T: Copy { + type Output = T; + + fn index(&self, index: Axis) -> &Self::Output { + let var_name = &self[index as usize]; + var_name + } + } +} +"#, + ); + + check_assist( + generate_mut_trait_impl, + r#" +//- minicore: index +mod foo { + mod bar { + pub enum Axis { X = 0, Y = 1, Z = 2 } + + impl core::ops::Index$0 for [T; 3] where T: Copy { + type Output = T; + + fn index(&self, index: Axis) -> &Self::Output { + let var_name = &self[index as usize]; + var_name + } + } + } +} +"#, + r#" +mod foo { + mod bar { + pub enum Axis { X = 0, Y = 1, Z = 2 } + + $0impl core::ops::IndexMut for [T; 3] where T: Copy { + fn index_mut(&mut self, index: Axis) -> &mut Self::Output { + let var_name = &self[index as usize]; + var_name + } + } + + impl core::ops::Index for [T; 3] where T: Copy { + type Output = T; + + fn index(&self, index: Axis) -> &Self::Output { + let var_name = &self[index as usize]; + var_name + } + } + } +} +"#, + ); + } + #[test] fn test_generate_mut_trait_impl_not_applicable() { check_assist_not_applicable( From 687eeeafc8031f143698304b34d5fbdce6bb8e0e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 19 May 2025 08:40:59 +0200 Subject: [PATCH 07/80] Change import prefix default to be by crate The current default plain, tends to create non-uniform import blocks over time, some being relative, some being absolute. I believe we should encourage a different default here. --- src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs | 2 +- .../rust-analyzer/docs/book/src/configuration_generated.md | 2 +- src/tools/rust-analyzer/editors/code/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 03e5b1f6f4b6..f7158235ca4c 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -544,7 +544,7 @@ config_data! { /// Whether to prefer import paths containing a `prelude` module. imports_preferPrelude: bool = false, /// The path structure for newly inserted paths to use. - imports_prefix: ImportPrefixDef = ImportPrefixDef::Plain, + imports_prefix: ImportPrefixDef = ImportPrefixDef::ByCrate, /// Whether to prefix external (including std, core) crate imports with `::`. e.g. "use ::std::io::Read;". imports_prefixExternPrelude: bool = false, } diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md index 2ae73df61d0a..de1d0ea4a359 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md @@ -835,7 +835,7 @@ Whether to prefer import paths containing a `prelude` module. ## rust-analyzer.imports.prefix {#imports.prefix} -Default: `"plain"` +Default: `"crate"` The path structure for newly inserted paths to use. diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index a282eea99973..88a90aad8c9f 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -1927,7 +1927,7 @@ "properties": { "rust-analyzer.imports.prefix": { "markdownDescription": "The path structure for newly inserted paths to use.", - "default": "plain", + "default": "crate", "type": "string", "enum": [ "plain", From 31b4808432efc02ead21199f498ee9e68ac6724e Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 19 May 2025 15:34:00 +0300 Subject: [PATCH 08/80] Fix cache problems with lints level By removing the cache. --- .../src/handlers/missing_unsafe.rs | 43 +++++ .../crates/ide-diagnostics/src/lib.rs | 181 ++---------------- 2 files changed, 60 insertions(+), 164 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index 364bead34efa..6bd5417b25d7 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -915,4 +915,47 @@ fn foo() { "#, ); } + + #[test] + fn regression_19823() { + check_diagnostics( + r#" +pub trait FooTrait { + unsafe fn method1(); + unsafe fn method2(); +} + +unsafe fn some_unsafe_fn() {} + +macro_rules! impl_foo { + () => { + unsafe fn method1() { + some_unsafe_fn(); + } + unsafe fn method2() { + some_unsafe_fn(); + } + }; +} + +pub struct S1; +#[allow(unsafe_op_in_unsafe_fn)] +impl FooTrait for S1 { + unsafe fn method1() { + some_unsafe_fn(); + } + + unsafe fn method2() { + some_unsafe_fn(); + } +} + +pub struct S2; +#[allow(unsafe_op_in_unsafe_fn)] +impl FooTrait for S2 { + impl_foo!(); +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index 2af14ca949bf..72bd66d1c8bb 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -83,12 +83,11 @@ mod handlers { #[cfg(test)] mod tests; -use std::{collections::hash_map, iter, sync::LazyLock}; +use std::{iter, sync::LazyLock}; use either::Either; use hir::{ - Crate, DisplayTarget, HirFileId, InFile, Semantics, db::ExpandDatabase, - diagnostics::AnyDiagnostic, + Crate, DisplayTarget, InFile, Semantics, db::ExpandDatabase, diagnostics::AnyDiagnostic, }; use ide_db::{ EditionedFileId, FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, Severity, SnippetCap, @@ -513,13 +512,7 @@ pub fn semantic_diagnostics( // The edition isn't accurate (each diagnostics may have its own edition due to macros), // but it's okay as it's only being used for error recovery. - handle_lints( - &ctx.sema, - &mut FxHashMap::default(), - &mut lints, - &mut Vec::new(), - editioned_file_id.edition(db), - ); + handle_lints(&ctx.sema, &mut lints, editioned_file_id.edition(db)); res.retain(|d| d.severity != Severity::Allow); @@ -584,8 +577,6 @@ fn handle_diag_from_macros( true } -// `__RA_EVERY_LINT` is a fake lint group to allow every lint in proc macros - struct BuiltLint { lint: &'static Lint, groups: Vec<&'static str>, @@ -629,9 +620,7 @@ fn build_lints_map( fn handle_lints( sema: &Semantics<'_, RootDatabase>, - cache: &mut FxHashMap>, diagnostics: &mut [(InFile, &mut Diagnostic)], - cache_stack: &mut Vec, edition: Edition, ) { for (node, diag) in diagnostics { @@ -645,7 +634,8 @@ fn handle_lints( diag.severity = default_severity; } - let mut diag_severity = fill_lint_attrs(sema, node, cache, cache_stack, diag, edition); + let mut diag_severity = + lint_severity_at(sema, node, &lint_groups(&diag.code, edition), edition); if let outline_diag_severity @ Some(_) = find_outline_mod_lint_severity(sema, node, diag, edition) @@ -698,155 +688,22 @@ fn find_outline_mod_lint_severity( result } -#[derive(Debug, Clone, Copy)] -struct SeverityAttr { - severity: Severity, - /// This field counts how far we are from the main node. Bigger values mean more far. - /// - /// Note this isn't accurate: there can be gaps between values (created when merging severity maps). - /// The important thing is that if an attr is closer to the main node, it will have smaller value. - /// - /// This is necessary even though we take care to never overwrite a value from deeper nesting - /// because of lint groups. For example, in the following code: - /// ``` - /// #[warn(non_snake_case)] - /// mod foo { - /// #[allow(nonstandard_style)] - /// mod bar {} - /// } - /// ``` - /// We want to not warn on non snake case inside `bar`. If we are traversing this for the first - /// time, everything will be fine, because we will set `diag_severity` on the first matching group - /// and never overwrite it since then. But if `bar` is cached, the cache will contain both - /// `#[warn(non_snake_case)]` and `#[allow(nonstandard_style)]`, and without this field, we have - /// no way of differentiating between the two. - depth: u32, -} - -fn fill_lint_attrs( +fn lint_severity_at( sema: &Semantics<'_, RootDatabase>, node: &InFile, - cache: &mut FxHashMap>, - cache_stack: &mut Vec, - diag: &Diagnostic, + lint_groups: &LintGroups, edition: Edition, ) -> Option { - let mut collected_lint_attrs = FxHashMap::::default(); - let mut diag_severity = None; - - let mut ancestors = node.value.ancestors().peekable(); - let mut depth = 0; - loop { - let ancestor = ancestors.next().expect("we always return from top-level nodes"); - depth += 1; - - if ancestors.peek().is_none() { - // We don't want to insert too many nodes into cache, but top level nodes (aka. outline modules - // or macro expansions) need to touch the database so they seem like a good fit to cache. - - if let Some(cached) = cache.get_mut(&node.file_id) { - // This node (and everything above it) is already cached; the attribute is either here or nowhere. - - // Workaround for the borrow checker. - let cached = std::mem::take(cached); - - cached.iter().for_each(|(lint, severity)| { - for item in &*cache_stack { - let node_cache_entry = cache - .get_mut(item) - .expect("we always insert cached nodes into the cache map"); - let lint_cache_entry = node_cache_entry.entry(lint.clone()); - if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry { - // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs - // overwrite top attrs. - lint_cache_entry.insert(SeverityAttr { - severity: severity.severity, - depth: severity.depth + depth, - }); - } - } - }); - - let lints = lint_groups(&diag.code, edition); - let all_matching_groups = - lints.iter().filter_map(|lint_group| cached.get(lint_group)); - let cached_severity = - all_matching_groups.min_by_key(|it| it.depth).map(|it| it.severity); - - cache.insert(node.file_id, cached); - - return diag_severity.or(cached_severity); - } - - // Insert this node's descendants' attributes into any outline descendant, but not including this node. - // This must come before inserting this node's own attributes to preserve order. - collected_lint_attrs.drain().for_each(|(lint, severity)| { - if diag_severity.is_none() && lint_groups(&diag.code, edition).contains(&lint) { - diag_severity = Some(severity.severity); - } - - for item in &*cache_stack { - let node_cache_entry = cache - .get_mut(item) - .expect("we always insert cached nodes into the cache map"); - let lint_cache_entry = node_cache_entry.entry(lint.clone()); - if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry { - // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs - // overwrite top attrs. - lint_cache_entry.insert(severity); - } - } - }); - - cache_stack.push(node.file_id); - cache.insert(node.file_id, FxHashMap::default()); - - if let Some(ancestor) = ast::AnyHasAttrs::cast(ancestor) { - // Insert this node's attributes into any outline descendant, including this node. - lint_attrs(sema, ancestor, edition).for_each(|(lint, severity)| { - if diag_severity.is_none() && lint_groups(&diag.code, edition).contains(&lint) { - diag_severity = Some(severity); - } - - for item in &*cache_stack { - let node_cache_entry = cache - .get_mut(item) - .expect("we always insert cached nodes into the cache map"); - let lint_cache_entry = node_cache_entry.entry(lint.clone()); - if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry { - // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs - // overwrite top attrs. - lint_cache_entry.insert(SeverityAttr { severity, depth }); - } - } - }); - } - - let parent_node = sema.find_parent_file(node.file_id); - if let Some(parent_node) = parent_node { - let parent_severity = - fill_lint_attrs(sema, &parent_node, cache, cache_stack, diag, edition); - if diag_severity.is_none() { - diag_severity = parent_severity; - } - } - cache_stack.pop(); - return diag_severity; - } else if let Some(ancestor) = ast::AnyHasAttrs::cast(ancestor) { - lint_attrs(sema, ancestor, edition).for_each(|(lint, severity)| { - if diag_severity.is_none() && lint_groups(&diag.code, edition).contains(&lint) { - diag_severity = Some(severity); - } - - let lint_cache_entry = collected_lint_attrs.entry(lint); - if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry { - // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs - // overwrite top attrs. - lint_cache_entry.insert(SeverityAttr { severity, depth }); - } - }); - } - } + node.value + .ancestors() + .filter_map(ast::AnyHasAttrs::cast) + .find_map(|ancestor| { + lint_attrs(sema, ancestor, edition) + .find_map(|(lint, severity)| lint_groups.contains(&lint).then_some(severity)) + }) + .or_else(|| { + lint_severity_at(sema, &sema.find_parent_file(node.file_id)?, lint_groups, edition) + }) } fn lint_attrs<'a>( @@ -945,10 +802,6 @@ impl LintGroups { fn contains(&self, group: &str) -> bool { self.groups.contains(&group) || (self.inside_warnings && group == "warnings") } - - fn iter(&self) -> impl Iterator { - self.groups.iter().copied().chain(self.inside_warnings.then_some("warnings")) - } } fn lint_groups(lint: &DiagnosticCode, edition: Edition) -> LintGroups { From b21c9e7bfb0180b67b486013a7137fb200cb1076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= <69964857+Sa4dUs@users.noreply.github.com> Date: Tue, 6 May 2025 09:19:33 +0200 Subject: [PATCH 09/80] Split `autodiff` into `autodiff_forward` and `autodiff_reverse` Pending fix. ``` error: cannot find a built-in macro with name `autodiff_forward` --> library\core\src\macros\mod.rs:1542:5 | 1542 | / pub macro autodiff_forward($item:item) { 1543 | | /* compiler built-in */ 1544 | | } | |_____^ error: cannot find a built-in macro with name `autodiff_reverse` --> library\core\src\macros\mod.rs:1549:5 | 1549 | / pub macro autodiff_reverse($item:item) { 1550 | | /* compiler built-in */ 1551 | | } | |_____^ error: could not compile `core` (lib) due to 2 previous errors ``` --- compiler/rustc_builtin_macros/src/autodiff.rs | 41 +++++++++++++------ compiler/rustc_builtin_macros/src/lib.rs | 3 +- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_span/src/symbol.rs | 3 +- library/core/src/lib.rs | 2 +- library/core/src/macros/mod.rs | 14 +++++++ 6 files changed, 48 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 1ff4fc6aaab2..8073de15925e 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -88,25 +88,20 @@ mod llvm_enzyme { has_ret: bool, ) -> AutoDiffAttrs { let dcx = ecx.sess.dcx(); - let mode = name(&meta_item[1]); - let Ok(mode) = DiffMode::from_str(&mode) else { - dcx.emit_err(errors::AutoDiffInvalidMode { span: meta_item[1].span(), mode }); - return AutoDiffAttrs::error(); - }; // Now we check, whether the user wants autodiff in batch/vector mode, or scalar mode. // If he doesn't specify an integer (=width), we default to scalar mode, thus width=1. - let mut first_activity = 2; + let mut first_activity = 1; - let width = if let [_, _, x, ..] = &meta_item[..] + let width = if let [_, x, ..] = &meta_item[..] && let Some(x) = width(x) { - first_activity = 3; + first_activity = 2; match x.try_into() { Ok(x) => x, Err(_) => { dcx.emit_err(errors::AutoDiffInvalidWidth { - span: meta_item[2].span(), + span: meta_item[1].span(), width: x, }); return AutoDiffAttrs::error(); @@ -150,7 +145,7 @@ mod llvm_enzyme { }; AutoDiffAttrs { - mode, + mode: DiffMode::Error, width, ret_activity: *ret_activity, input_activity: input_activity.to_vec(), @@ -165,6 +160,24 @@ mod llvm_enzyme { ts.push(TokenTree::Token(comma.clone(), Spacing::Alone)); } + pub(crate) fn expand_forward( + ecx: &mut ExtCtxt<'_>, + expand_span: Span, + meta_item: &ast::MetaItem, + item: Annotatable, + ) -> Vec { + expand_with_mode(ecx, expand_span, meta_item, item, DiffMode::Forward) + } + + pub(crate) fn expand_reverse( + ecx: &mut ExtCtxt<'_>, + expand_span: Span, + meta_item: &ast::MetaItem, + item: Annotatable, + ) -> Vec { + expand_with_mode(ecx, expand_span, meta_item, item, DiffMode::Reverse) + } + /// We expand the autodiff macro to generate a new placeholder function which passes /// type-checking and can be called by users. The function body of the placeholder function will /// later be replaced on LLVM-IR level, so the design of the body is less important and for now @@ -198,11 +211,12 @@ mod llvm_enzyme { /// ``` /// FIXME(ZuseZ4): Once autodiff is enabled by default, make this a doc comment which is checked /// in CI. - pub(crate) fn expand( + pub(crate) fn expand_with_mode( ecx: &mut ExtCtxt<'_>, expand_span: Span, meta_item: &ast::MetaItem, mut item: Annotatable, + mode: DiffMode, ) -> Vec { if cfg!(not(llvm_enzyme)) { ecx.sess.dcx().emit_err(errors::AutoDiffSupportNotBuild { span: meta_item.span }); @@ -289,7 +303,8 @@ mod llvm_enzyme { ts.pop(); let ts: TokenStream = TokenStream::from_iter(ts); - let x: AutoDiffAttrs = from_ast(ecx, &meta_item_vec, has_ret); + let mut x: AutoDiffAttrs = from_ast(ecx, &meta_item_vec, has_ret); + x.mode = mode; if !x.is_active() { // We encountered an error, so we return the original item. // This allows us to potentially parse other attributes. @@ -1017,4 +1032,4 @@ mod llvm_enzyme { } } -pub(crate) use llvm_enzyme::expand; +pub(crate) use llvm_enzyme::{expand_forward, expand_reverse}; diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 9cd4d17059a0..a89b3642f7e5 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -112,7 +112,8 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { register_attr! { alloc_error_handler: alloc_error_handler::expand, - autodiff: autodiff::expand, + autodiff_forward: autodiff::expand_forward, + autodiff_reverse: autodiff::expand_reverse, bench: test::expand_bench, cfg_accessible: cfg_accessible::Expander, cfg_eval: cfg_eval::expand, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5c0d0cf47969..5aff24f7aa0c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -255,7 +255,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_generic_attr(hir_id, attr, target, Target::Fn); self.check_proc_macro(hir_id, target, ProcMacroKind::Derive) } - [sym::autodiff, ..] => { + [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => { self.check_autodiff(hir_id, attr, span, target) } [sym::coroutine, ..] => { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index efae6250b072..bb19b5761bb1 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -531,7 +531,8 @@ symbols! { audit_that, augmented_assignments, auto_traits, - autodiff, + autodiff_forward, + autodiff_reverse, automatically_derived, avx, avx10_target_feature, diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e605d7e0d784..aaa8c872f985 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -229,7 +229,7 @@ pub mod assert_matches { /// Unstable module containing the unstable `autodiff` macro. pub mod autodiff { #[unstable(feature = "autodiff", issue = "124509")] - pub use crate::macros::builtin::autodiff; + pub use crate::macros::builtin::{autodiff_forward, autodiff_reverse}; } #[unstable(feature = "contracts", issue = "128044")] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 7dc8c060cd5b..dc50ad6a0907 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1536,6 +1536,20 @@ pub(crate) mod builtin { /* compiler built-in */ } + #[unstable(feature = "autodiff", issue = "124509")] + #[allow_internal_unstable(rustc_attrs)] + #[rustc_builtin_macro] + pub macro autodiff_forward($item:item) { + /* compiler built-in */ + } + + #[unstable(feature = "autodiff", issue = "124509")] + #[allow_internal_unstable(rustc_attrs)] + #[rustc_builtin_macro] + pub macro autodiff_reverse($item:item) { + /* compiler built-in */ + } + /// Asserts that a boolean expression is `true` at runtime. /// /// This will invoke the [`panic!`] macro if the provided expression cannot be From 9efad3a87bb69ce62f9a5b1703e1b8decfe5c4a6 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 27 Apr 2025 16:18:29 +0200 Subject: [PATCH 10/80] Add data_ptr method to Mutex and RwLock --- library/std/src/sync/poison/mutex.rs | 6 ++++++ library/std/src/sync/poison/rwlock.rs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 1c29c619edc3..372bf0a30292 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -608,6 +608,12 @@ impl Mutex { let data = self.data.get_mut(); poison::map_result(self.poison.borrow(), |()| data) } + + /// Returns a raw pointer to the underlying data. + #[unstable(feature = "mutex_data_ptr", issue = "140368")] + pub fn data_ptr(&self) -> *mut T { + self.data.get() + } } #[stable(feature = "mutex_from", since = "1.24.0")] diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index 6976c0a64e23..0b32a2f1be15 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -634,6 +634,12 @@ impl RwLock { let data = self.data.get_mut(); poison::map_result(self.poison.borrow(), |()| data) } + + /// Returns a raw pointer to the underlying data. + #[unstable(feature = "rwlock_data_ptr", issue = "140368")] + pub fn data_ptr(&self) -> *mut T { + self.data.get() + } } #[stable(feature = "rust1", since = "1.0.0")] From 9d6c5a88a18405eb53e91645d35371ab089f0a37 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 21 May 2025 08:05:44 +0200 Subject: [PATCH 11/80] Add more docs to new data_ptr methods --- library/std/src/sync/poison/mutex.rs | 5 +++++ library/std/src/sync/poison/rwlock.rs | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 372bf0a30292..30325be685c3 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -610,6 +610,11 @@ impl Mutex { } /// Returns a raw pointer to the underlying data. + /// + /// The returned pointer is always non-null and properly aligned, but it is + /// the user's responsibility to ensure that any reads and writes through it + /// are properly synchronized to avoid data races, and that it is not read + /// or written through after the mutex is dropped. #[unstable(feature = "mutex_data_ptr", issue = "140368")] pub fn data_ptr(&self) -> *mut T { self.data.get() diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index 0b32a2f1be15..a060e2ea57a7 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -636,6 +636,11 @@ impl RwLock { } /// Returns a raw pointer to the underlying data. + /// + /// The returned pointer is always non-null and properly aligned, but it is + /// the user's responsibility to ensure that any reads and writes through it + /// are properly synchronized to avoid data races, and that it is not read + /// or written through after the lock is dropped. #[unstable(feature = "rwlock_data_ptr", issue = "140368")] pub fn data_ptr(&self) -> *mut T { self.data.get() From 20589bd6050ff9596348c751231ac84b7538adb4 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 21 May 2025 08:06:04 +0200 Subject: [PATCH 12/80] Add ReentrantLock::data_ptr --- library/std/src/sync/reentrant_lock.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs index 96a4cf12659c..727252f03a24 100644 --- a/library/std/src/sync/reentrant_lock.rs +++ b/library/std/src/sync/reentrant_lock.rs @@ -349,6 +349,17 @@ impl ReentrantLock { } } + /// Returns a raw pointer to the underlying data. + /// + /// The returned pointer is always non-null and properly aligned, but it is + /// the user's responsibility to ensure that any reads through it are + /// properly synchronized to avoid data races, and that it is not read + /// through after the lock is dropped. + #[unstable(feature = "reentrant_lock_data_ptr", issue = "140368")] + pub fn data_ptr(&self) -> *const T { + &raw const self.data + } + unsafe fn increment_lock_count(&self) -> Option<()> { unsafe { *self.lock_count.get() = (*self.lock_count.get()).checked_add(1)?; From b725cf6af8c5a709828d649c86185b30872219ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Sat, 10 May 2025 00:11:06 +0000 Subject: [PATCH 13/80] Disable autodiff bootstrapping --- compiler/rustc_builtin_macros/src/errors.rs | 8 ----- compiler/rustc_builtin_macros/src/lib.rs | 2 +- library/core/src/lib.rs | 1 + library/core/src/macros/mod.rs | 40 ++++++++++++--------- library/std/src/lib.rs | 7 ++-- 5 files changed, 30 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index b28f7d312d93..b3cc460abbfc 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -187,14 +187,6 @@ mod autodiff { pub(crate) act: String, } - #[derive(Diagnostic)] - #[diag(builtin_macros_autodiff_mode)] - pub(crate) struct AutoDiffInvalidMode { - #[primary_span] - pub(crate) span: Span, - pub(crate) mode: String, - } - #[derive(Diagnostic)] #[diag(builtin_macros_autodiff_width)] pub(crate) struct AutoDiffInvalidWidth { diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index a89b3642f7e5..b16f3cff5cfb 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -5,10 +5,10 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(not(bootstrap), feature(autodiff))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] -#![feature(autodiff)] #![feature(box_patterns)] #![feature(decl_macro)] #![feature(if_let_guard)] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index aaa8c872f985..e1982116994b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -226,6 +226,7 @@ pub mod assert_matches { // We don't export this through #[macro_export] for now, to avoid breakage. #[unstable(feature = "autodiff", issue = "124509")] +#[cfg(not(bootstrap))] /// Unstable module containing the unstable `autodiff` macro. pub mod autodiff { #[unstable(feature = "autodiff", issue = "124509")] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index dc50ad6a0907..99a4ab52b6c5 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1519,33 +1519,39 @@ pub(crate) mod builtin { ($file:expr $(,)?) => {{ /* compiler built-in */ }}; } - /// Automatic Differentiation macro which allows generating a new function to compute - /// the derivative of a given function. It may only be applied to a function. - /// The expected usage syntax is - /// `#[autodiff(NAME, MODE, INPUT_ACTIVITIES, OUTPUT_ACTIVITY)]` - /// where: - /// NAME is a string that represents a valid function name. - /// MODE is any of Forward, Reverse, ForwardFirst, ReverseFirst. - /// INPUT_ACTIVITIES consists of one valid activity for each input parameter. - /// OUTPUT_ACTIVITY must not be set if we implicitly return nothing (or explicitly return - /// `-> ()`). Otherwise it must be set to one of the allowed activities. - #[unstable(feature = "autodiff", issue = "124509")] - #[allow_internal_unstable(rustc_attrs)] - #[rustc_builtin_macro] - pub macro autodiff($item:item) { - /* compiler built-in */ - } - + /// the derivative of a given function in the forward mode of differentiation. + /// It may only be applied to a function. + /// + /// The expected usage syntax is: + /// `#[autodiff_forward(NAME, INPUT_ACTIVITIES, OUTPUT_ACTIVITY)]` + /// + /// - `NAME`: A string that represents a valid function name. + /// - `INPUT_ACTIVITIES`: Specifies one valid activity for each input parameter. + /// - `OUTPUT_ACTIVITY`: Must not be set if the function implicitly returns nothing + /// (or explicitly returns `-> ()`). Otherwise, it must be set to one of the allowed activities. #[unstable(feature = "autodiff", issue = "124509")] #[allow_internal_unstable(rustc_attrs)] #[rustc_builtin_macro] + #[cfg(not(bootstrap))] pub macro autodiff_forward($item:item) { /* compiler built-in */ } + /// Automatic Differentiation macro which allows generating a new function to compute + /// the derivative of a given function in the reverse mode of differentiation. + /// It may only be applied to a function. + /// + /// The expected usage syntax is: + /// `#[autodiff_reverse(NAME, INPUT_ACTIVITIES, OUTPUT_ACTIVITY)]` + /// + /// - `NAME`: A string that represents a valid function name. + /// - `INPUT_ACTIVITIES`: Specifies one valid activity for each input parameter. + /// - `OUTPUT_ACTIVITY`: Must not be set if the function implicitly returns nothing + /// (or explicitly returns `-> ()`). Otherwise, it must be set to one of the allowed activities. #[unstable(feature = "autodiff", issue = "124509")] #[allow_internal_unstable(rustc_attrs)] #[rustc_builtin_macro] + #[cfg(not(bootstrap))] pub macro autodiff_reverse($item:item) { /* compiler built-in */ } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ef41b47384d6..0ac674d98906 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -276,12 +276,12 @@ // tidy-alphabetical-start // stabilization was reverted after it hit beta +#![cfg_attr(not(bootstrap), feature(autodiff))] #![feature(alloc_error_handler)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] #![feature(asm_experimental_arch)] -#![feature(autodiff)] #![feature(cfg_sanitizer_cfi)] #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] @@ -636,12 +636,15 @@ pub mod simd { #[doc(inline)] pub use crate::std_float::StdFloat; } + #[unstable(feature = "autodiff", issue = "124509")] +#[cfg(not(bootstrap))] /// This module provides support for automatic differentiation. pub mod autodiff { /// This macro handles automatic differentiation. - pub use core::autodiff::autodiff; + pub use core::autodiff::{autodiff_forward, autodiff_reverse}; } + #[stable(feature = "futures_api", since = "1.36.0")] pub mod task { //! Types and Traits for working with asynchronous tasks. From 2041de7083c114025646220068d3943be517af4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Sat, 10 May 2025 00:37:15 +0000 Subject: [PATCH 14/80] Update codegen and pretty tests UI tests are pending, will depend on error messages change. --- tests/codegen/autodiff/batched.rs | 8 +++--- tests/codegen/autodiff/identical_fnc.rs | 6 ++--- tests/codegen/autodiff/inline.rs | 4 +-- tests/codegen/autodiff/scalar.rs | 4 +-- tests/codegen/autodiff/sret.rs | 4 +-- tests/pretty/autodiff/autodiff_forward.pp | 2 +- tests/pretty/autodiff/autodiff_forward.rs | 30 +++++++++++------------ tests/pretty/autodiff/autodiff_reverse.pp | 2 +- tests/pretty/autodiff/autodiff_reverse.rs | 12 ++++----- tests/pretty/autodiff/inherent_impl.pp | 2 +- tests/pretty/autodiff/inherent_impl.rs | 4 +-- 11 files changed, 39 insertions(+), 39 deletions(-) diff --git a/tests/codegen/autodiff/batched.rs b/tests/codegen/autodiff/batched.rs index e00471164055..d27aed50e6cc 100644 --- a/tests/codegen/autodiff/batched.rs +++ b/tests/codegen/autodiff/batched.rs @@ -11,11 +11,11 @@ #![feature(autodiff)] -use std::autodiff::autodiff; +use std::autodiff::autodiff_forward; -#[autodiff(d_square3, Forward, Dual, DualOnly)] -#[autodiff(d_square2, Forward, 4, Dual, DualOnly)] -#[autodiff(d_square1, Forward, 4, Dual, Dual)] +#[autodiff_forward(d_square3, Dual, DualOnly)] +#[autodiff_forward(d_square2, 4, Dual, DualOnly)] +#[autodiff_forward(d_square1, 4, Dual, Dual)] #[no_mangle] fn square(x: &f32) -> f32 { x * x diff --git a/tests/codegen/autodiff/identical_fnc.rs b/tests/codegen/autodiff/identical_fnc.rs index 1c3277f52b48..1c25b3d09ab0 100644 --- a/tests/codegen/autodiff/identical_fnc.rs +++ b/tests/codegen/autodiff/identical_fnc.rs @@ -11,14 +11,14 @@ // identical function calls in the LLVM-IR, while having two different calls in the Rust code. #![feature(autodiff)] -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; -#[autodiff(d_square, Reverse, Duplicated, Active)] +#[autodiff_reverse(d_square, Duplicated, Active)] fn square(x: &f64) -> f64 { x * x } -#[autodiff(d_square2, Reverse, Duplicated, Active)] +#[autodiff_reverse(d_square2, Duplicated, Active)] fn square2(x: &f64) -> f64 { x * x } diff --git a/tests/codegen/autodiff/inline.rs b/tests/codegen/autodiff/inline.rs index e90faa4aa380..65bed170207c 100644 --- a/tests/codegen/autodiff/inline.rs +++ b/tests/codegen/autodiff/inline.rs @@ -4,9 +4,9 @@ #![feature(autodiff)] -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; -#[autodiff(d_square, Reverse, Duplicated, Active)] +#[autodiff_reverse(d_square, Duplicated, Active)] fn square(x: &f64) -> f64 { x * x } diff --git a/tests/codegen/autodiff/scalar.rs b/tests/codegen/autodiff/scalar.rs index 85358f5fcb69..096b4209e84a 100644 --- a/tests/codegen/autodiff/scalar.rs +++ b/tests/codegen/autodiff/scalar.rs @@ -3,9 +3,9 @@ //@ needs-enzyme #![feature(autodiff)] -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; -#[autodiff(d_square, Reverse, Duplicated, Active)] +#[autodiff_reverse(d_square, Duplicated, Active)] #[no_mangle] fn square(x: &f64) -> f64 { x * x diff --git a/tests/codegen/autodiff/sret.rs b/tests/codegen/autodiff/sret.rs index 5ead90041edc..d2fa85e3e378 100644 --- a/tests/codegen/autodiff/sret.rs +++ b/tests/codegen/autodiff/sret.rs @@ -9,10 +9,10 @@ #![feature(autodiff)] -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; #[no_mangle] -#[autodiff(df, Reverse, Active, Active, Active)] +#[autodiff_reverse(df, Active, Active, Active)] fn primal(x: f32, y: f32) -> f64 { (x * x * y) as f64 } diff --git a/tests/pretty/autodiff/autodiff_forward.pp b/tests/pretty/autodiff/autodiff_forward.pp index 8253603e8079..a2525abc8320 100644 --- a/tests/pretty/autodiff/autodiff_forward.pp +++ b/tests/pretty/autodiff/autodiff_forward.pp @@ -13,7 +13,7 @@ extern crate std; // Test that forward mode ad macros are expanded correctly. -use std::autodiff::autodiff; +use std::autodiff::{autodiff_forward, autodiff_reverse}; #[rustc_autodiff] #[inline(never)] diff --git a/tests/pretty/autodiff/autodiff_forward.rs b/tests/pretty/autodiff/autodiff_forward.rs index ae974f9b4dbf..181b6ebc7704 100644 --- a/tests/pretty/autodiff/autodiff_forward.rs +++ b/tests/pretty/autodiff/autodiff_forward.rs @@ -7,48 +7,48 @@ // Test that forward mode ad macros are expanded correctly. -use std::autodiff::autodiff; +use std::autodiff::{autodiff_forward, autodiff_reverse}; -#[autodiff(df1, Forward, Dual, Const, Dual)] +#[autodiff_forward(df1, Dual, Const, Dual)] pub fn f1(x: &[f64], y: f64) -> f64 { unimplemented!() } -#[autodiff(df2, Forward, Dual, Const, Const)] +#[autodiff_forward(df2, Dual, Const, Const)] pub fn f2(x: &[f64], y: f64) -> f64 { unimplemented!() } -#[autodiff(df3, Forward, Dual, Const, Const)] +#[autodiff_forward(df3, Dual, Const, Const)] pub fn f3(x: &[f64], y: f64) -> f64 { unimplemented!() } // Not the most interesting derivative, but who are we to judge -#[autodiff(df4, Forward)] +#[autodiff_forward(df4)] pub fn f4() {} // We want to be sure that the same function can be differentiated in different ways -#[autodiff(df5_rev, Reverse, Duplicated, Const, Active)] -#[autodiff(df5_x, Forward, Dual, Const, Const)] -#[autodiff(df5_y, Forward, Const, Dual, Const)] +#[autodiff_reverse(df5_rev, Duplicated, Const, Active)] +#[autodiff_forward(df5_x, Dual, Const, Const)] +#[autodiff_forward(df5_y, Const, Dual, Const)] pub fn f5(x: &[f64], y: f64) -> f64 { unimplemented!() } struct DoesNotImplDefault; -#[autodiff(df6, Forward, Const)] +#[autodiff_forward(df6, Const)] pub fn f6() -> DoesNotImplDefault { unimplemented!() } // Make sure, that we add the None for the default return. -#[autodiff(df7, Forward, Const)] +#[autodiff_forward(df7, Const)] pub fn f7(x: f32) -> () {} -#[autodiff(f8_1, Forward, Dual, DualOnly)] -#[autodiff(f8_2, Forward, 4, Dual, DualOnly)] -#[autodiff(f8_3, Forward, 4, Dual, Dual)] +#[autodiff_forward(f8_1, Dual, DualOnly)] +#[autodiff_forward(f8_2, 4, Dual, DualOnly)] +#[autodiff_forward(f8_3, 4, Dual, Dual)] #[no_mangle] fn f8(x: &f32) -> f32 { unimplemented!() @@ -56,8 +56,8 @@ fn f8(x: &f32) -> f32 { // We want to make sure that we can use the macro for functions defined inside of functions pub fn f9() { - #[autodiff(d_inner_1, Forward, Dual, DualOnly)] - #[autodiff(d_inner_2, Forward, Dual, Dual)] + #[autodiff_forward(d_inner_1, Dual, DualOnly)] + #[autodiff_forward(d_inner_2, Dual, Dual)] fn inner(x: f32) -> f32 { x * x } diff --git a/tests/pretty/autodiff/autodiff_reverse.pp b/tests/pretty/autodiff/autodiff_reverse.pp index 31920694a3ad..e67c3443ddef 100644 --- a/tests/pretty/autodiff/autodiff_reverse.pp +++ b/tests/pretty/autodiff/autodiff_reverse.pp @@ -13,7 +13,7 @@ extern crate std; // Test that reverse mode ad macros are expanded correctly. -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; #[rustc_autodiff] #[inline(never)] diff --git a/tests/pretty/autodiff/autodiff_reverse.rs b/tests/pretty/autodiff/autodiff_reverse.rs index 3c024272f407..d37e5e3eb4ce 100644 --- a/tests/pretty/autodiff/autodiff_reverse.rs +++ b/tests/pretty/autodiff/autodiff_reverse.rs @@ -7,18 +7,18 @@ // Test that reverse mode ad macros are expanded correctly. -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; -#[autodiff(df1, Reverse, Duplicated, Const, Active)] +#[autodiff_reverse(df1, Duplicated, Const, Active)] pub fn f1(x: &[f64], y: f64) -> f64 { unimplemented!() } // Not the most interesting derivative, but who are we to judge -#[autodiff(df2, Reverse)] +#[autodiff_reverse(df2)] pub fn f2() {} -#[autodiff(df3, Reverse, Duplicated, Const, Active)] +#[autodiff_reverse(df3, Duplicated, Const, Active)] pub fn f3(x: &[f64], y: f64) -> f64 { unimplemented!() } @@ -27,12 +27,12 @@ enum Foo { Reverse } use Foo::Reverse; // What happens if we already have Reverse in type (enum variant decl) and value (enum variant // constructor) namespace? > It's expected to work normally. -#[autodiff(df4, Reverse, Const)] +#[autodiff_reverse(df4, Const)] pub fn f4(x: f32) { unimplemented!() } -#[autodiff(df5, Reverse, DuplicatedOnly, Duplicated)] +#[autodiff_reverse(df5, DuplicatedOnly, Duplicated)] pub fn f5(x: *const f32, y: &f32) { unimplemented!() } diff --git a/tests/pretty/autodiff/inherent_impl.pp b/tests/pretty/autodiff/inherent_impl.pp index 97ac766b6b99..d18061b2dbde 100644 --- a/tests/pretty/autodiff/inherent_impl.pp +++ b/tests/pretty/autodiff/inherent_impl.pp @@ -11,7 +11,7 @@ extern crate std; //@ pretty-compare-only //@ pp-exact:inherent_impl.pp -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; struct Foo { a: f64, diff --git a/tests/pretty/autodiff/inherent_impl.rs b/tests/pretty/autodiff/inherent_impl.rs index 59de93f7e0ff..11ff209f9d89 100644 --- a/tests/pretty/autodiff/inherent_impl.rs +++ b/tests/pretty/autodiff/inherent_impl.rs @@ -5,7 +5,7 @@ //@ pretty-compare-only //@ pp-exact:inherent_impl.pp -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; struct Foo { a: f64, @@ -17,7 +17,7 @@ trait MyTrait { } impl MyTrait for Foo { - #[autodiff(df, Reverse, Const, Active, Active)] + #[autodiff_reverse(df, Const, Active, Active)] fn f(&self, x: f64) -> f64 { self.a * 0.25 * (x * x - 1.0 - 2.0 * x.ln()) } From f92d84cc6e0770c0d8f3dc775bafdf7f8786db61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Sat, 10 May 2025 00:52:47 +0000 Subject: [PATCH 15/80] Initial naive implementation using `Symbols` to represent autodiff modes (`Forward`, `Reverse`) Since the mode is no longer part of `meta_item`, we must insert it manually (otherwise macro expansion with `#[rustc_autodiff]` won't work). This can be revised later if a more structured representation becomes necessary (using enums, annotated structs, etc). Some tests are currently failing. I'll address them next. --- compiler/rustc_builtin_macros/src/autodiff.rs | 28 +++++++++++++------ compiler/rustc_span/src/symbol.rs | 2 ++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 8073de15925e..d60bb0ae5cbd 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -259,29 +259,41 @@ mod llvm_enzyme { // create TokenStream from vec elemtents: // meta_item doesn't have a .tokens field let mut ts: Vec = vec![]; - if meta_item_vec.len() < 2 { - // At the bare minimum, we need a fnc name and a mode, even for a dummy function with no - // input and output args. + if meta_item_vec.len() < 1 { + // At the bare minimum, we need a fnc name. dcx.emit_err(errors::AutoDiffMissingConfig { span: item.span() }); return vec![item]; } - meta_item_inner_to_ts(&meta_item_vec[1], &mut ts); + let mode_symbol = match mode { + DiffMode::Forward => sym::Forward, + DiffMode::Reverse => sym::Reverse, + _ => unreachable!("Unsupported mode: {:?}", mode), + }; + + // Insert mode token + let mode_token = Token::new(TokenKind::Ident(mode_symbol, false.into()), Span::default()); + ts.insert(0, TokenTree::Token(mode_token, Spacing::Joint)); + ts.insert( + 1, + TokenTree::Token(Token::new(TokenKind::Comma, Span::default()), Spacing::Alone), + ); // Now, if the user gave a width (vector aka batch-mode ad), then we copy it. // If it is not given, we default to 1 (scalar mode). let start_position; let kind: LitKind = LitKind::Integer; let symbol; - if meta_item_vec.len() >= 3 - && let Some(width) = width(&meta_item_vec[2]) + if meta_item_vec.len() >= 2 + && let Some(width) = width(&meta_item_vec[1]) { - start_position = 3; + start_position = 2; symbol = Symbol::intern(&width.to_string()); } else { - start_position = 2; + start_position = 1; symbol = sym::integer(1); } + let l: Lit = Lit { kind, symbol, suffix: None }; let t = Token::new(TokenKind::Literal(l), Span::default()); let comma = Token::new(TokenKind::Comma, Span::default()); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index bb19b5761bb1..9dff87e0a001 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -253,6 +253,7 @@ symbols! { FnMut, FnOnce, Formatter, + Forward, From, FromIterator, FromResidual, @@ -348,6 +349,7 @@ symbols! { Result, ResumeTy, Return, + Reverse, Right, Rust, RustaceansAreAwesome, From 8dd62e8188d08baeb5d28cb221241cb61a65e532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Sat, 10 May 2025 21:50:06 +0000 Subject: [PATCH 16/80] Update UI tests --- compiler/rustc_builtin_macros/messages.ftl | 1 - compiler/rustc_builtin_macros/src/autodiff.rs | 6 +- tests/ui/autodiff/autodiff_illegal.rs | 60 +++++--------- tests/ui/autodiff/autodiff_illegal.stderr | 83 ++++++++----------- tests/ui/autodiff/auxiliary/my_macro.rs | 2 +- tests/ui/autodiff/visibility.rs | 9 +- .../autodiff/visibility.std_autodiff.stderr | 26 +++--- ...ature-gate-autodiff-use.has_support.stderr | 8 +- ...eature-gate-autodiff-use.no_support.stderr | 12 +-- .../feature-gate-autodiff-use.rs | 4 +- .../feature-gate-autodiff.has_support.stderr | 8 +- .../feature-gate-autodiff.no_support.stderr | 8 +- .../ui/feature-gates/feature-gate-autodiff.rs | 6 +- 13 files changed, 101 insertions(+), 132 deletions(-) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 73be954cefd7..4796f3a18889 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -71,7 +71,6 @@ builtin_macros_assert_requires_expression = macro requires an expression as an a builtin_macros_autodiff = autodiff must be applied to function builtin_macros_autodiff_missing_config = autodiff requires at least a name and mode -builtin_macros_autodiff_mode = unknown Mode: `{$mode}`. Use `Forward` or `Reverse` builtin_macros_autodiff_mode_activity = {$act} can not be used in {$mode} Mode builtin_macros_autodiff_not_build = this rustc version does not support autodiff builtin_macros_autodiff_number_activities = expected {$expected} activities, but found {$found} diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index d60bb0ae5cbd..dc3bb8ab52a5 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -86,6 +86,7 @@ mod llvm_enzyme { ecx: &mut ExtCtxt<'_>, meta_item: &ThinVec, has_ret: bool, + mode: DiffMode, ) -> AutoDiffAttrs { let dcx = ecx.sess.dcx(); @@ -145,7 +146,7 @@ mod llvm_enzyme { }; AutoDiffAttrs { - mode: DiffMode::Error, + mode, width, ret_activity: *ret_activity, input_activity: input_activity.to_vec(), @@ -315,8 +316,7 @@ mod llvm_enzyme { ts.pop(); let ts: TokenStream = TokenStream::from_iter(ts); - let mut x: AutoDiffAttrs = from_ast(ecx, &meta_item_vec, has_ret); - x.mode = mode; + let x: AutoDiffAttrs = from_ast(ecx, &meta_item_vec, has_ret, mode); if !x.is_active() { // We encountered an error, so we return the original item. // This allows us to potentially parse other attributes. diff --git a/tests/ui/autodiff/autodiff_illegal.rs b/tests/ui/autodiff/autodiff_illegal.rs index a916bd8b857b..a53b6d5e5898 100644 --- a/tests/ui/autodiff/autodiff_illegal.rs +++ b/tests/ui/autodiff/autodiff_illegal.rs @@ -7,38 +7,38 @@ // Test that invalid ad macros give nice errors and don't ICE. -use std::autodiff::autodiff; +use std::autodiff::{autodiff_forward, autodiff_reverse}; // We can't use Duplicated on scalars -#[autodiff(df1, Reverse, Duplicated)] +#[autodiff_reverse(df1, Duplicated)] pub fn f1(x: f64) { //~^ ERROR Duplicated can not be used for this type unimplemented!() } // Too many activities -#[autodiff(df3, Reverse, Duplicated, Const)] +#[autodiff_reverse(df3, Duplicated, Const)] pub fn f3(x: f64) { //~^^ ERROR expected 1 activities, but found 2 unimplemented!() } // To few activities -#[autodiff(df4, Reverse)] +#[autodiff_reverse(df4)] pub fn f4(x: f64) { //~^^ ERROR expected 1 activities, but found 0 unimplemented!() } // We can't use Dual in Reverse mode -#[autodiff(df5, Reverse, Dual)] +#[autodiff_reverse(df5, Dual)] pub fn f5(x: f64) { //~^^ ERROR Dual can not be used in Reverse Mode unimplemented!() } // We can't use Duplicated in Forward mode -#[autodiff(df6, Forward, Duplicated)] +#[autodiff_forward(df6, Duplicated)] pub fn f6(x: f64) { //~^^ ERROR Duplicated can not be used in Forward Mode //~^^ ERROR Duplicated can not be used for this type @@ -46,36 +46,36 @@ pub fn f6(x: f64) { } fn dummy() { - #[autodiff(df7, Forward, Dual)] + #[autodiff_forward(df7, Dual)] let mut x = 5; //~^ ERROR autodiff must be applied to function - #[autodiff(df7, Forward, Dual)] + #[autodiff_forward(df7, Dual)] x = x + 3; //~^^ ERROR attributes on expressions are experimental [E0658] //~^^ ERROR autodiff must be applied to function - #[autodiff(df7, Forward, Dual)] + #[autodiff_forward(df7, Dual)] let add_one_v2 = |x: u32| -> u32 { x + 1 }; //~^ ERROR autodiff must be applied to function } // Malformed, where args? -#[autodiff] +#[autodiff_forward] pub fn f7(x: f64) { //~^ ERROR autodiff requires at least a name and mode unimplemented!() } // Malformed, where args? -#[autodiff()] +#[autodiff_forward()] pub fn f8(x: f64) { //~^ ERROR autodiff requires at least a name and mode unimplemented!() } // Invalid attribute syntax -#[autodiff = ""] +#[autodiff_forward = ""] pub fn f9(x: f64) { //~^ ERROR autodiff requires at least a name and mode unimplemented!() @@ -84,29 +84,15 @@ pub fn f9(x: f64) { fn fn_exists() {} // We colide with an already existing function -#[autodiff(fn_exists, Reverse, Active)] +#[autodiff_reverse(fn_exists, Active)] pub fn f10(x: f64) { //~^^ ERROR the name `fn_exists` is defined multiple times [E0428] unimplemented!() } -// Malformed, missing a mode -#[autodiff(df11)] -pub fn f11() { - //~^ ERROR autodiff requires at least a name and mode - unimplemented!() -} - -// Invalid Mode -#[autodiff(df12, Debug)] -pub fn f12() { - //~^^ ERROR unknown Mode: `Debug`. Use `Forward` or `Reverse` - unimplemented!() -} - // Invalid, please pick one Mode // or use two autodiff macros. -#[autodiff(df13, Forward, Reverse)] +#[autodiff_reverse(df13, Reverse)] pub fn f13() { //~^^ ERROR did not recognize Activity: `Reverse` unimplemented!() @@ -117,7 +103,7 @@ struct Foo {} // We can't handle Active structs, because that would mean (in the general case), that we would // need to allocate and initialize arbitrary user types. We have Duplicated/Dual input args for // that. FIXME: Give a nicer error and suggest to the user to have a `&mut Foo` input instead. -#[autodiff(df14, Reverse, Active, Active)] +#[autodiff_reverse(df14, Active, Active)] fn f14(x: f32) -> Foo { unimplemented!() } @@ -127,14 +113,14 @@ type MyFloat = f32; // We would like to support type alias to f32/f64 in argument type in the future, // but that requires us to implement our checks at a later stage // like THIR which has type information available. -#[autodiff(df15, Reverse, Active, Active)] +#[autodiff_reverse(df15, Active, Active)] fn f15(x: MyFloat) -> f32 { //~^^ ERROR failed to resolve: use of undeclared type `MyFloat` [E0433] unimplemented!() } // We would like to support type alias to f32/f64 in return type in the future -#[autodiff(df16, Reverse, Active, Active)] +#[autodiff_reverse(df16, Active, Active)] fn f16(x: f32) -> MyFloat { unimplemented!() } @@ -145,40 +131,40 @@ struct F64Trans { } // We would like to support `#[repr(transparent)]` f32/f64 wrapper in return type in the future -#[autodiff(df17, Reverse, Active, Active)] +#[autodiff_reverse(df17, Active, Active)] fn f17(x: f64) -> F64Trans { unimplemented!() } // We would like to support `#[repr(transparent)]` f32/f64 wrapper in argument type in the future -#[autodiff(df18, Reverse, Active, Active)] +#[autodiff_reverse(df18, Active, Active)] fn f18(x: F64Trans) -> f64 { //~^^ ERROR failed to resolve: use of undeclared type `F64Trans` [E0433] unimplemented!() } // Invalid return activity -#[autodiff(df19, Forward, Dual, Active)] +#[autodiff_forward(df19, Dual, Active)] fn f19(x: f32) -> f32 { //~^^ ERROR invalid return activity Active in Forward Mode unimplemented!() } -#[autodiff(df20, Reverse, Active, Dual)] +#[autodiff_reverse(df20, Active, Dual)] fn f20(x: f32) -> f32 { //~^^ ERROR invalid return activity Dual in Reverse Mode unimplemented!() } // Duplicated cannot be used as return activity -#[autodiff(df21, Reverse, Active, Duplicated)] +#[autodiff_reverse(df21, Active, Duplicated)] fn f21(x: f32) -> f32 { //~^^ ERROR invalid return activity Duplicated in Reverse Mode unimplemented!() } struct DoesNotImplDefault; -#[autodiff(df22, Forward, Dual)] +#[autodiff_forward(df22, Dual)] pub fn f22() -> DoesNotImplDefault { //~^^ ERROR the function or associated item `default` exists for tuple `(DoesNotImplDefault, DoesNotImplDefault)`, but its trait bounds were not satisfied unimplemented!() diff --git a/tests/ui/autodiff/autodiff_illegal.stderr b/tests/ui/autodiff/autodiff_illegal.stderr index b119f61b8ae6..ad6f10af4678 100644 --- a/tests/ui/autodiff/autodiff_illegal.stderr +++ b/tests/ui/autodiff/autodiff_illegal.stderr @@ -1,8 +1,8 @@ error[E0658]: attributes on expressions are experimental --> $DIR/autodiff_illegal.rs:53:5 | -LL | #[autodiff(df7, Forward, Dual)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[autodiff_forward(df7, Dual)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #15701 for more information = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable @@ -17,26 +17,26 @@ LL | pub fn f1(x: f64) { error: expected 1 activities, but found 2 --> $DIR/autodiff_illegal.rs:20:1 | -LL | #[autodiff(df3, Reverse, Duplicated, Const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[autodiff_reverse(df3, Duplicated, Const)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: expected 1 activities, but found 0 --> $DIR/autodiff_illegal.rs:27:1 | -LL | #[autodiff(df4, Reverse)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[autodiff_reverse(df4)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: Dual can not be used in Reverse Mode --> $DIR/autodiff_illegal.rs:34:1 | -LL | #[autodiff(df5, Reverse, Dual)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[autodiff_reverse(df5, Dual)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Duplicated can not be used in Forward Mode --> $DIR/autodiff_illegal.rs:41:1 | -LL | #[autodiff(df6, Forward, Duplicated)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[autodiff_forward(df6, Duplicated)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Duplicated can not be used for this type --> $DIR/autodiff_illegal.rs:42:14 @@ -95,69 +95,54 @@ error[E0428]: the name `fn_exists` is defined multiple times LL | fn fn_exists() {} | -------------- previous definition of the value `fn_exists` here ... -LL | #[autodiff(fn_exists, Reverse, Active)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fn_exists` redefined here +LL | #[autodiff_reverse(fn_exists, Active)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fn_exists` redefined here | = note: `fn_exists` must be defined only once in the value namespace of this module -error: autodiff requires at least a name and mode - --> $DIR/autodiff_illegal.rs:95:1 - | -LL | / pub fn f11() { -LL | | -LL | | unimplemented!() -LL | | } - | |_^ - -error: unknown Mode: `Debug`. Use `Forward` or `Reverse` - --> $DIR/autodiff_illegal.rs:101:18 - | -LL | #[autodiff(df12, Debug)] - | ^^^^^ - error: did not recognize Activity: `Reverse` - --> $DIR/autodiff_illegal.rs:109:27 + --> $DIR/autodiff_illegal.rs:95:26 | -LL | #[autodiff(df13, Forward, Reverse)] - | ^^^^^^^ +LL | #[autodiff_reverse(df13, Reverse)] + | ^^^^^^^ error: invalid return activity Active in Forward Mode - --> $DIR/autodiff_illegal.rs:161:1 + --> $DIR/autodiff_illegal.rs:147:1 | -LL | #[autodiff(df19, Forward, Dual, Active)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[autodiff_forward(df19, Dual, Active)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid return activity Dual in Reverse Mode - --> $DIR/autodiff_illegal.rs:167:1 + --> $DIR/autodiff_illegal.rs:153:1 | -LL | #[autodiff(df20, Reverse, Active, Dual)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[autodiff_reverse(df20, Active, Dual)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid return activity Duplicated in Reverse Mode - --> $DIR/autodiff_illegal.rs:174:1 + --> $DIR/autodiff_illegal.rs:160:1 | -LL | #[autodiff(df21, Reverse, Active, Duplicated)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[autodiff_reverse(df21, Active, Duplicated)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0433]: failed to resolve: use of undeclared type `MyFloat` - --> $DIR/autodiff_illegal.rs:130:1 + --> $DIR/autodiff_illegal.rs:116:1 | -LL | #[autodiff(df15, Reverse, Active, Active)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `MyFloat` +LL | #[autodiff_reverse(df15, Active, Active)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `MyFloat` error[E0433]: failed to resolve: use of undeclared type `F64Trans` - --> $DIR/autodiff_illegal.rs:154:1 + --> $DIR/autodiff_illegal.rs:140:1 | -LL | #[autodiff(df18, Reverse, Active, Active)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `F64Trans` +LL | #[autodiff_reverse(df18, Active, Active)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared type `F64Trans` error[E0599]: the function or associated item `default` exists for tuple `(DoesNotImplDefault, DoesNotImplDefault)`, but its trait bounds were not satisfied - --> $DIR/autodiff_illegal.rs:181:1 + --> $DIR/autodiff_illegal.rs:167:1 | LL | struct DoesNotImplDefault; | ------------------------- doesn't satisfy `DoesNotImplDefault: Default` -LL | #[autodiff(df22, Forward, Dual)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function or associated item cannot be called on `(DoesNotImplDefault, DoesNotImplDefault)` due to unsatisfied trait bounds +LL | #[autodiff_forward(df22, Dual)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function or associated item cannot be called on `(DoesNotImplDefault, DoesNotImplDefault)` due to unsatisfied trait bounds | = note: the following trait bounds were not satisfied: `DoesNotImplDefault: Default` @@ -168,7 +153,7 @@ LL + #[derive(Default)] LL | struct DoesNotImplDefault; | -error: aborting due to 23 previous errors +error: aborting due to 21 previous errors Some errors have detailed explanations: E0428, E0433, E0599, E0658. For more information about an error, try `rustc --explain E0428`. diff --git a/tests/ui/autodiff/auxiliary/my_macro.rs b/tests/ui/autodiff/auxiliary/my_macro.rs index 217631a33c9b..1d5a6de14548 100644 --- a/tests/ui/autodiff/auxiliary/my_macro.rs +++ b/tests/ui/autodiff/auxiliary/my_macro.rs @@ -3,6 +3,6 @@ use proc_macro::TokenStream; #[proc_macro_attribute] #[macro_use] -pub fn autodiff(_attr: TokenStream, item: TokenStream) -> TokenStream { +pub fn autodiff_forward(_attr: TokenStream, item: TokenStream) -> TokenStream { item // identity proc-macro } diff --git a/tests/ui/autodiff/visibility.rs b/tests/ui/autodiff/visibility.rs index dfaec03aef01..a84df75e7996 100644 --- a/tests/ui/autodiff/visibility.rs +++ b/tests/ui/autodiff/visibility.rs @@ -6,12 +6,11 @@ #![feature(autodiff)] #[cfg(std_autodiff)] -use std::autodiff::autodiff; - +use std::autodiff::autodiff_forward; extern crate my_macro; -use my_macro::autodiff; // bring `autodiff` in scope +use my_macro::autodiff_forward; // bring `autodiff_forward` in scope -#[autodiff] -//[std_autodiff]~^^^ ERROR the name `autodiff` is defined multiple times +#[autodiff_forward(dfoo)] +//[std_autodiff]~^^^ ERROR the name `autodiff_forward` is defined multiple times //[std_autodiff]~^^ ERROR this rustc version does not support autodiff fn foo() {} diff --git a/tests/ui/autodiff/visibility.std_autodiff.stderr b/tests/ui/autodiff/visibility.std_autodiff.stderr index 720c9a00170e..e45f1139012a 100644 --- a/tests/ui/autodiff/visibility.std_autodiff.stderr +++ b/tests/ui/autodiff/visibility.std_autodiff.stderr @@ -1,23 +1,23 @@ -error[E0252]: the name `autodiff` is defined multiple times - --> $DIR/visibility.rs:12:5 +error[E0252]: the name `autodiff_forward` is defined multiple times + --> $DIR/visibility.rs:11:5 | -LL | use std::autodiff::autodiff; - | ----------------------- previous import of the macro `autodiff` here -... -LL | use my_macro::autodiff; // bring `autodiff` in scope - | ^^^^^^^^^^^^^^^^^^ `autodiff` reimported here +LL | use std::autodiff::autodiff_forward; + | ------------------------------- previous import of the macro `autodiff_forward` here +LL | extern crate my_macro; +LL | use my_macro::autodiff_forward; // bring `autodiff_forward` in scope + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `autodiff_forward` reimported here | - = note: `autodiff` must be defined only once in the macro namespace of this module + = note: `autodiff_forward` must be defined only once in the macro namespace of this module help: you can use `as` to change the binding name of the import | -LL | use my_macro::autodiff as other_autodiff; // bring `autodiff` in scope - | +++++++++++++++++ +LL | use my_macro::autodiff_forward as other_autodiff_forward; // bring `autodiff_forward` in scope + | +++++++++++++++++++++++++ error: this rustc version does not support autodiff - --> $DIR/visibility.rs:14:1 + --> $DIR/visibility.rs:13:1 | -LL | #[autodiff] - | ^^^^^^^^^^^ +LL | #[autodiff_forward(dfoo)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/feature-gates/feature-gate-autodiff-use.has_support.stderr b/tests/ui/feature-gates/feature-gate-autodiff-use.has_support.stderr index 15ef257fbd84..e5edd8e45e6c 100644 --- a/tests/ui/feature-gates/feature-gate-autodiff-use.has_support.stderr +++ b/tests/ui/feature-gates/feature-gate-autodiff-use.has_support.stderr @@ -1,8 +1,8 @@ error[E0658]: use of unstable library feature `autodiff` --> $DIR/feature-gate-autodiff-use.rs:13:3 | -LL | #[autodiff(dfoo, Reverse)] - | ^^^^^^^^ +LL | #[autodiff_reverse(dfoo)] + | ^^^^^^^^^^^^^^^^ | = note: see issue #124509 for more information = help: add `#![feature(autodiff)]` to the crate attributes to enable @@ -11,8 +11,8 @@ LL | #[autodiff(dfoo, Reverse)] error[E0658]: use of unstable library feature `autodiff` --> $DIR/feature-gate-autodiff-use.rs:9:5 | -LL | use std::autodiff::autodiff; - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | use std::autodiff::autodiff_reverse; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #124509 for more information = help: add `#![feature(autodiff)]` to the crate attributes to enable diff --git a/tests/ui/feature-gates/feature-gate-autodiff-use.no_support.stderr b/tests/ui/feature-gates/feature-gate-autodiff-use.no_support.stderr index f59e49554520..65ba033b3589 100644 --- a/tests/ui/feature-gates/feature-gate-autodiff-use.no_support.stderr +++ b/tests/ui/feature-gates/feature-gate-autodiff-use.no_support.stderr @@ -1,8 +1,8 @@ error[E0658]: use of unstable library feature `autodiff` --> $DIR/feature-gate-autodiff-use.rs:13:3 | -LL | #[autodiff(dfoo, Reverse)] - | ^^^^^^^^ +LL | #[autodiff_reverse(dfoo)] + | ^^^^^^^^^^^^^^^^ | = note: see issue #124509 for more information = help: add `#![feature(autodiff)]` to the crate attributes to enable @@ -11,14 +11,14 @@ LL | #[autodiff(dfoo, Reverse)] error: this rustc version does not support autodiff --> $DIR/feature-gate-autodiff-use.rs:13:1 | -LL | #[autodiff(dfoo, Reverse)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[autodiff_reverse(dfoo)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0658]: use of unstable library feature `autodiff` --> $DIR/feature-gate-autodiff-use.rs:9:5 | -LL | use std::autodiff::autodiff; - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | use std::autodiff::autodiff_reverse; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #124509 for more information = help: add `#![feature(autodiff)]` to the crate attributes to enable diff --git a/tests/ui/feature-gates/feature-gate-autodiff-use.rs b/tests/ui/feature-gates/feature-gate-autodiff-use.rs index 602e830b0b21..2864b786c121 100644 --- a/tests/ui/feature-gates/feature-gate-autodiff-use.rs +++ b/tests/ui/feature-gates/feature-gate-autodiff-use.rs @@ -6,11 +6,11 @@ #![crate_type = "lib"] -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; //[has_support]~^ ERROR use of unstable library feature `autodiff` //[no_support]~^^ ERROR use of unstable library feature `autodiff` -#[autodiff(dfoo, Reverse)] +#[autodiff_reverse(dfoo)] //[has_support]~^ ERROR use of unstable library feature `autodiff` [E0658] //[no_support]~^^ ERROR use of unstable library feature `autodiff` [E0658] //[no_support]~| ERROR this rustc version does not support autodiff diff --git a/tests/ui/feature-gates/feature-gate-autodiff.has_support.stderr b/tests/ui/feature-gates/feature-gate-autodiff.has_support.stderr index c25cf7d33737..dcbaba716459 100644 --- a/tests/ui/feature-gates/feature-gate-autodiff.has_support.stderr +++ b/tests/ui/feature-gates/feature-gate-autodiff.has_support.stderr @@ -1,12 +1,12 @@ -error: cannot find attribute `autodiff` in this scope +error: cannot find attribute `autodiff_reverse` in this scope --> $DIR/feature-gate-autodiff.rs:9:3 | -LL | #[autodiff(dfoo, Reverse)] - | ^^^^^^^^ +LL | #[autodiff_reverse(dfoo)] + | ^^^^^^^^^^^^^^^^ | help: consider importing this attribute macro | -LL + use std::autodiff::autodiff; +LL + use std::autodiff::autodiff_reverse; | error: aborting due to 1 previous error diff --git a/tests/ui/feature-gates/feature-gate-autodiff.no_support.stderr b/tests/ui/feature-gates/feature-gate-autodiff.no_support.stderr index c25cf7d33737..dcbaba716459 100644 --- a/tests/ui/feature-gates/feature-gate-autodiff.no_support.stderr +++ b/tests/ui/feature-gates/feature-gate-autodiff.no_support.stderr @@ -1,12 +1,12 @@ -error: cannot find attribute `autodiff` in this scope +error: cannot find attribute `autodiff_reverse` in this scope --> $DIR/feature-gate-autodiff.rs:9:3 | -LL | #[autodiff(dfoo, Reverse)] - | ^^^^^^^^ +LL | #[autodiff_reverse(dfoo)] + | ^^^^^^^^^^^^^^^^ | help: consider importing this attribute macro | -LL + use std::autodiff::autodiff; +LL + use std::autodiff::autodiff_reverse; | error: aborting due to 1 previous error diff --git a/tests/ui/feature-gates/feature-gate-autodiff.rs b/tests/ui/feature-gates/feature-gate-autodiff.rs index 4249b229a698..adb35cb8e335 100644 --- a/tests/ui/feature-gates/feature-gate-autodiff.rs +++ b/tests/ui/feature-gates/feature-gate-autodiff.rs @@ -6,7 +6,7 @@ // This checks that without the autodiff feature enabled, we can't use it. -#[autodiff(dfoo, Reverse)] -//[has_support]~^ ERROR cannot find attribute `autodiff` in this scope -//[no_support]~^^ ERROR cannot find attribute `autodiff` in this scope +#[autodiff_reverse(dfoo)] +//[has_support]~^ ERROR cannot find attribute `autodiff_reverse` in this scope +//[no_support]~^^ ERROR cannot find attribute `autodiff_reverse` in this scope fn foo() {} From 8917ff602446372e45abed7ab3a58dc879638b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Tue, 20 May 2025 12:36:12 +0000 Subject: [PATCH 17/80] Update generic tests --- tests/codegen/autodiff/generic.rs | 4 ++-- tests/pretty/autodiff/autodiff_forward.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/codegen/autodiff/generic.rs b/tests/codegen/autodiff/generic.rs index 15e7d8a49574..2f674079be02 100644 --- a/tests/codegen/autodiff/generic.rs +++ b/tests/codegen/autodiff/generic.rs @@ -3,9 +3,9 @@ //@ needs-enzyme #![feature(autodiff)] -use std::autodiff::autodiff; +use std::autodiff::autodiff_reverse; -#[autodiff(d_square, Reverse, Duplicated, Active)] +#[autodiff_reverse(d_square, Duplicated, Active)] fn square + Copy>(x: &T) -> T { *x * *x } diff --git a/tests/pretty/autodiff/autodiff_forward.rs b/tests/pretty/autodiff/autodiff_forward.rs index 181b6ebc7704..e23a1b3e241e 100644 --- a/tests/pretty/autodiff/autodiff_forward.rs +++ b/tests/pretty/autodiff/autodiff_forward.rs @@ -64,7 +64,7 @@ pub fn f9() { } // Make sure we can handle generics -#[autodiff(d_square, Reverse, Duplicated, Active)] +#[autodiff_reverse(d_square, Duplicated, Active)] pub fn f10 + Copy>(x: &T) -> T { *x * *x } From 226db317b1fcf13fc2cebea92855a30ff7877f32 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 21 May 2025 18:31:14 +0300 Subject: [PATCH 18/80] Correctly set the span of the proc_macro crate's Group delimiters Previously only the open delimiter's span was set, and this caused... weird problems. --- .../src/server_impl/rust_analyzer_span.rs | 4 +++- .../crates/proc-macro-srv/src/server_impl/token_id.rs | 3 ++- .../proc-macro-srv/src/server_impl/token_stream.rs | 11 +++++++++-- .../crates/proc-macro-srv/src/tests/mod.rs | 2 +- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index 64b40e7b9437..e0c6e68f8037 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -258,7 +258,9 @@ impl server::TokenStream for RaSpanServer { &mut self, stream: Self::TokenStream, ) -> Vec> { - stream.into_bridge() + stream.into_bridge(&mut |first, second| { + server::Span::join(self, first, second).unwrap_or(first) + }) } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs index 24a67bf45c8d..d55b269f868d 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs @@ -238,7 +238,8 @@ impl server::TokenStream for TokenIdServer { &mut self, stream: Self::TokenStream, ) -> Vec> { - stream.into_bridge() + // Can't join with `TokenId`. + stream.into_bridge(&mut |first, _second| first) } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs index 072557913c2b..c5019a591722 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs @@ -56,7 +56,10 @@ impl TokenStream { self.token_trees.is_empty() } - pub(crate) fn into_bridge(self) -> Vec> { + pub(crate) fn into_bridge( + self, + join_spans: &mut dyn FnMut(S, S) -> S, + ) -> Vec> { let mut result = Vec::new(); let mut iter = self.token_trees.into_iter(); while let Some(tree) = iter.next() { @@ -98,7 +101,11 @@ impl TokenStream { token_trees: iter.by_ref().take(subtree.usize_len()).collect(), }) }, - span: bridge::DelimSpan::from_single(subtree.delimiter.open), + span: bridge::DelimSpan { + open: subtree.delimiter.open, + close: subtree.delimiter.close, + entire: join_spans(subtree.delimiter.open, subtree.delimiter.close), + }, })) } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs index 3868fee40fba..3a6ce639d135 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs @@ -144,7 +144,7 @@ fn test_fn_like_macro_clone_ident_subtree() { SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024 IDENT ident 42:2@0..5#ROOT2024 PUNCH , [alone] 42:2@5..6#ROOT2024 - SUBTREE [] 42:2@7..8#ROOT2024 42:2@7..8#ROOT2024"#]], + SUBTREE [] 42:2@7..9#ROOT2024 42:2@7..9#ROOT2024"#]], ); } From 8acb1b5f0b3955f114677ee1725d39024202f16b Mon Sep 17 00:00:00 2001 From: David Barsky Date: Wed, 21 May 2025 09:47:29 -0400 Subject: [PATCH 19/80] internal: fix `integrated_benchmarks` to make actual edits --- .../src/integrated_benchmarks.rs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs index 49ebffa909ac..84b7888258f8 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs @@ -147,7 +147,7 @@ fn integrated_completion_benchmark() { let _it = stdx::timeit("change"); let mut text = host.analysis().file_text(file_id).unwrap().to_string(); let completion_offset = - patch(&mut text, "db.struct_data(self.id)", "sel;\ndb.struct_data(self.id)") + patch(&mut text, "db.struct_signature(self.id)", "sel;\ndb.struct_signature(self.id)") + "sel".len(); let mut change = ChangeWithProcMacros::default(); change.change_file(file_id, Some(text)); @@ -197,9 +197,11 @@ fn integrated_completion_benchmark() { let completion_offset = { let _it = stdx::timeit("change"); let mut text = host.analysis().file_text(file_id).unwrap().to_string(); - let completion_offset = - patch(&mut text, "sel;\ndb.struct_data(self.id)", ";sel;\ndb.struct_data(self.id)") - + ";sel".len(); + let completion_offset = patch( + &mut text, + "sel;\ndb.struct_signature(self.id)", + ";sel;\ndb.struct_signature(self.id)", + ) + ";sel".len(); let mut change = ChangeWithProcMacros::default(); change.change_file(file_id, Some(text)); host.apply_change(change); @@ -247,9 +249,11 @@ fn integrated_completion_benchmark() { let completion_offset = { let _it = stdx::timeit("change"); let mut text = host.analysis().file_text(file_id).unwrap().to_string(); - let completion_offset = - patch(&mut text, "sel;\ndb.struct_data(self.id)", "self.;\ndb.struct_data(self.id)") - + "self.".len(); + let completion_offset = patch( + &mut text, + "sel;\ndb.struct_signature(self.id)", + "self.;\ndb.struct_signature(self.id)", + ) + "self.".len(); let mut change = ChangeWithProcMacros::default(); change.change_file(file_id, Some(text)); host.apply_change(change); @@ -366,7 +370,7 @@ fn integrated_diagnostics_benchmark() { { let _it = stdx::timeit("change"); let mut text = host.analysis().file_text(file_id).unwrap().to_string(); - patch(&mut text, "db.struct_data(self.id)", "();\ndb.struct_data(self.id)"); + patch(&mut text, "db.struct_signature(self.id)", "();\ndb.struct_signature(self.id)"); let mut change = ChangeWithProcMacros::default(); change.change_file(file_id, Some(text)); host.apply_change(change); From 24a416cc5714ab7129fa91f4e94f6dd877675b05 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 22 May 2025 07:55:06 +0200 Subject: [PATCH 20/80] Support `transmute_unchecked` intrinsic for mir-eval --- src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index 7cf948b178e4..90c52ee96f1f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -1121,7 +1121,7 @@ impl Evaluator<'_> { // We don't call any drop glue yet, so there is nothing here Ok(()) } - "transmute" => { + "transmute" | "transmute_unchecked" => { let [arg] = args else { return Err(MirEvalError::InternalError( "transmute arg is not provided".into(), From fb181cf6603ebe56a9cc39b9a1bcbc39a226f190 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 22 May 2025 07:35:59 +0000 Subject: [PATCH 21/80] Remove rust-analyzer.vs from other editors --- .../docs/book/src/other_editors.md | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/src/tools/rust-analyzer/docs/book/src/other_editors.md b/src/tools/rust-analyzer/docs/book/src/other_editors.md index 1eac7dd2c256..896df52af5f9 100644 --- a/src/tools/rust-analyzer/docs/book/src/other_editors.md +++ b/src/tools/rust-analyzer/docs/book/src/other_editors.md @@ -364,30 +364,6 @@ binary](./rust_analyzer_binary.html). There are multiple rust-analyzer extensions for Visual Studio 2022 on Windows: -### rust-analyzer.vs - -(License: Creative Commons Attribution-NonCommercial-ShareAlike 4.0 -International) - -[Visual Studio -Marketplace](https://marketplace.visualstudio.com/items?itemName=kitamstudios.RustAnalyzer) - -[GitHub](https://github.com/kitamstudios/rust-analyzer/) - -Support for Rust development in the Visual Studio IDE is enabled by the -[rust-analyzer](https://marketplace.visualstudio.com/items?itemName=kitamstudios.RustAnalyzer) -package. Either click on the download link or install from IDE’s -extension manager. For now [Visual Studio -2022](https://visualstudio.microsoft.com/downloads/) is required. All -editions are supported viz. Community, Professional & Enterprise. The -package aims to provide 0-friction installation and therefore comes -loaded with most things required including rust-analyzer binary. If -anything it needs is missing, appropriate errors / warnings will guide -the user. E.g. cargo.exe needs to be in path and the package will tell -you as much. This package is under rapid active development. So if you -encounter any issues please file it at -[rust-analyzer.vs](https://github.com/kitamstudios/rust-analyzer/). - ### VS RustAnalyzer (License: GPL) From f0096aea4020b354415268539cb4fddf6fc5f48d Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Fri, 23 May 2025 01:01:21 +0300 Subject: [PATCH 22/80] Normalize when checking for uninhabited types for pattern exhaustiveness checking --- .../crates/hir-ty/src/diagnostics/expr.rs | 10 +++++--- .../diagnostics/match_check/pat_analysis.rs | 24 +++++++++++++----- .../crates/hir-ty/src/inhabitedness.rs | 23 ++++++++++++++--- .../crates/hir-ty/src/mir/lower.rs | 24 ++++++++++-------- .../src/handlers/non_exhaustive_let.rs | 25 +++++++++++++++++++ 5 files changed, 81 insertions(+), 25 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index e4a23cbbacff..8665e9d33fcb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -25,7 +25,7 @@ use triomphe::Arc; use typed_arena::Arena; use crate::{ - Adjust, InferenceResult, Interner, Ty, TyExt, TyKind, + Adjust, InferenceResult, Interner, TraitEnvironment, Ty, TyExt, TyKind, db::HirDatabase, diagnostics::match_check::{ self, @@ -74,8 +74,9 @@ impl BodyValidationDiagnostic { let _p = tracing::info_span!("BodyValidationDiagnostic::collect").entered(); let infer = db.infer(owner); let body = db.body(owner); + let env = db.trait_environment_for_body(owner); let mut validator = - ExprValidator { owner, body, infer, diagnostics: Vec::new(), validate_lints }; + ExprValidator { owner, body, infer, diagnostics: Vec::new(), validate_lints, env }; validator.validate_body(db); validator.diagnostics } @@ -85,6 +86,7 @@ struct ExprValidator { owner: DefWithBodyId, body: Arc, infer: Arc, + env: Arc, diagnostics: Vec, validate_lints: bool, } @@ -190,7 +192,7 @@ impl ExprValidator { return; } - let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db); + let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db, self.env.clone()); let pattern_arena = Arena::new(); let mut m_arms = Vec::with_capacity(arms.len()); @@ -317,7 +319,7 @@ impl ExprValidator { return; }; let pattern_arena = Arena::new(); - let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db); + let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db, self.env.clone()); for stmt in &**statements { let &Statement::Let { pat, initializer, else_branch: None, .. } = stmt else { continue; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index 785277d70c64..dd82a0f45ca4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -12,9 +12,10 @@ use rustc_pattern_analysis::{ }; use smallvec::{SmallVec, smallvec}; use stdx::never; +use triomphe::Arc; use crate::{ - AdtId, Interner, Scalar, Ty, TyExt, TyKind, + AdtId, Interner, Scalar, TraitEnvironment, Ty, TyExt, TyKind, db::HirDatabase, infer::normalize, inhabitedness::{is_enum_variant_uninhabited_from, is_ty_uninhabited_from}, @@ -69,13 +70,19 @@ pub(crate) struct MatchCheckCtx<'db> { body: DefWithBodyId, pub(crate) db: &'db dyn HirDatabase, exhaustive_patterns: bool, + env: Arc, } impl<'db> MatchCheckCtx<'db> { - pub(crate) fn new(module: ModuleId, body: DefWithBodyId, db: &'db dyn HirDatabase) -> Self { + pub(crate) fn new( + module: ModuleId, + body: DefWithBodyId, + db: &'db dyn HirDatabase, + env: Arc, + ) -> Self { let def_map = module.crate_def_map(db); let exhaustive_patterns = def_map.is_unstable_feature_enabled(&sym::exhaustive_patterns); - Self { module, body, db, exhaustive_patterns } + Self { module, body, db, exhaustive_patterns, env } } pub(crate) fn compute_match_usefulness( @@ -100,7 +107,7 @@ impl<'db> MatchCheckCtx<'db> { } fn is_uninhabited(&self, ty: &Ty) -> bool { - is_ty_uninhabited_from(self.db, ty, self.module) + is_ty_uninhabited_from(self.db, ty, self.module, self.env.clone()) } /// Returns whether the given ADT is from another crate declared `#[non_exhaustive]`. @@ -459,8 +466,13 @@ impl PatCx for MatchCheckCtx<'_> { } else { let mut variants = IndexVec::with_capacity(enum_data.variants.len()); for &(variant, _) in enum_data.variants.iter() { - let is_uninhabited = - is_enum_variant_uninhabited_from(cx.db, variant, subst, cx.module); + let is_uninhabited = is_enum_variant_uninhabited_from( + cx.db, + variant, + subst, + cx.module, + self.env.clone(), + ); let visibility = if is_uninhabited { VariantVisibility::Empty } else { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs index e0c3279d3fb0..e81a5e3c3114 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs @@ -7,17 +7,24 @@ use chalk_ir::{ }; use hir_def::{AdtId, EnumVariantId, ModuleId, VariantId, visibility::Visibility}; use rustc_hash::FxHashSet; +use triomphe::Arc; use crate::{ - Binders, Interner, Substitution, Ty, TyKind, consteval::try_const_usize, db::HirDatabase, + AliasTy, Binders, Interner, Substitution, TraitEnvironment, Ty, TyKind, + consteval::try_const_usize, db::HirDatabase, }; // FIXME: Turn this into a query, it can be quite slow /// Checks whether a type is visibly uninhabited from a particular module. -pub(crate) fn is_ty_uninhabited_from(db: &dyn HirDatabase, ty: &Ty, target_mod: ModuleId) -> bool { +pub(crate) fn is_ty_uninhabited_from( + db: &dyn HirDatabase, + ty: &Ty, + target_mod: ModuleId, + env: Arc, +) -> bool { let _p = tracing::info_span!("is_ty_uninhabited_from", ?ty).entered(); let mut uninhabited_from = - UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() }; + UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default(), env }; let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST); inhabitedness == BREAK_VISIBLY_UNINHABITED } @@ -29,11 +36,12 @@ pub(crate) fn is_enum_variant_uninhabited_from( variant: EnumVariantId, subst: &Substitution, target_mod: ModuleId, + env: Arc, ) -> bool { let _p = tracing::info_span!("is_enum_variant_uninhabited_from").entered(); let mut uninhabited_from = - UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() }; + UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default(), env }; let inhabitedness = uninhabited_from.visit_variant(variant.into(), subst); inhabitedness == BREAK_VISIBLY_UNINHABITED } @@ -44,6 +52,7 @@ struct UninhabitedFrom<'a> { // guard for preventing stack overflow in non trivial non terminating types max_depth: usize, db: &'a dyn HirDatabase, + env: Arc, } const CONTINUE_OPAQUELY_INHABITED: ControlFlow = Continue(()); @@ -78,6 +87,12 @@ impl TypeVisitor for UninhabitedFrom<'_> { Some(0) | None => CONTINUE_OPAQUELY_INHABITED, Some(1..) => item_ty.super_visit_with(self, outer_binder), }, + TyKind::Alias(AliasTy::Projection(projection)) => { + // FIXME: I think this currently isn't used for monomorphized bodies, so there is no need to handle + // `TyKind::AssociatedType`, but perhaps in the future it will. + let normalized = self.db.normalize_projection(projection.clone(), self.env.clone()); + self.visit_ty(&normalized, outer_binder) + } _ => CONTINUE_OPAQUELY_INHABITED, }; self.recursive_ty.remove(ty); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 7fcc89e5183a..e6caf2d8d97a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -25,7 +25,7 @@ use syntax::TextRange; use triomphe::Arc; use crate::{ - Adjust, Adjustment, AutoBorrow, CallableDefId, TyBuilder, TyExt, + Adjust, Adjustment, AutoBorrow, CallableDefId, TraitEnvironment, TyBuilder, TyExt, consteval::ConstEvalError, db::{HirDatabase, InternedClosure, InternedClosureId}, display::{DisplayTarget, HirDisplay, hir_display_with_store}, @@ -79,6 +79,7 @@ struct MirLowerCtx<'db> { infer: &'db InferenceResult, resolver: Resolver<'db>, drop_scopes: Vec, + env: Arc, } // FIXME: Make this smaller, its stored in database queries @@ -288,6 +289,7 @@ impl<'ctx> MirLowerCtx<'ctx> { closures: vec![], }; let resolver = owner.resolver(db); + let env = db.trait_environment_for_body(owner); MirLowerCtx { result: mir, @@ -300,6 +302,7 @@ impl<'ctx> MirLowerCtx<'ctx> { labeled_loop_blocks: Default::default(), discr_temp: None, drop_scopes: vec![DropScope::default()], + env, } } @@ -944,10 +947,7 @@ impl<'ctx> MirLowerCtx<'ctx> { let cast_kind = if source_ty.as_reference().is_some() { CastKind::PointerCoercion(PointerCast::ArrayToPointer) } else { - let mut table = InferenceTable::new( - self.db, - self.db.trait_environment_for_body(self.owner), - ); + let mut table = InferenceTable::new(self.db, self.env.clone()); cast_kind(&mut table, &source_ty, &target_ty)? }; @@ -1412,11 +1412,8 @@ impl<'ctx> MirLowerCtx<'ctx> { } fn lower_literal_to_operand(&mut self, ty: Ty, l: &Literal) -> Result { - let size = || { - self.db - .layout_of_ty(ty.clone(), self.db.trait_environment_for_body(self.owner)) - .map(|it| it.size.bytes_usize()) - }; + let size = + || self.db.layout_of_ty(ty.clone(), self.env.clone()).map(|it| it.size.bytes_usize()); const USIZE_SIZE: usize = size_of::(); let bytes: Box<[_]> = match l { hir_def::hir::Literal::String(b) => { @@ -1723,7 +1720,12 @@ impl<'ctx> MirLowerCtx<'ctx> { } fn is_uninhabited(&self, expr_id: ExprId) -> bool { - is_ty_uninhabited_from(self.db, &self.infer[expr_id], self.owner.module(self.db)) + is_ty_uninhabited_from( + self.db, + &self.infer[expr_id], + self.owner.module(self.db), + self.env.clone(), + ) } /// This function push `StorageLive` statement for the binding, and applies changes to add `StorageDead` and diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs index 35cefd239752..f20b6dea1227 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs @@ -106,4 +106,29 @@ fn test(x: Result) { "#, ); } + + #[test] + fn empty_patterns_normalize() { + check_diagnostics( + r#" +enum Infallible {} + +trait Foo { + type Assoc; +} +enum Enum { + A, + B(T::Assoc), +} + +impl Foo for () { + type Assoc = Infallible; +} + +fn foo(v: Enum<()>) { + let Enum::A = v; +} + "#, + ); + } } From 69ba323c1ca1faba14ace7cec19dd5b738367960 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 23 May 2025 12:57:07 +0200 Subject: [PATCH 23/80] Bump salsa --- src/tools/rust-analyzer/Cargo.lock | 241 ++---------------- src/tools/rust-analyzer/Cargo.toml | 7 +- .../rust-analyzer/crates/base-db/src/input.rs | 12 +- .../rust-analyzer/crates/base-db/src/lib.rs | 4 +- .../crates/hir-def/src/lang_item.rs | 2 +- .../crates/hir-def/src/nameres.rs | 8 +- .../crates/hir-def/src/test_db.rs | 23 +- .../crates/hir-ty/src/test_db.rs | 22 +- .../rust-analyzer/crates/ide-db/src/lib.rs | 4 +- .../query-group-macro/tests/logger_db.rs | 40 +-- 10 files changed, 83 insertions(+), 280 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index bd8146defae9..01de430925dc 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -17,15 +17,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - [[package]] name = "allocator-api2" version = "0.2.21" @@ -124,12 +115,9 @@ dependencies = [ [[package]] name = "boxcar" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6740c6e2fc6360fa57c35214c7493826aee95993926092606f27c983b40837be" -dependencies = [ - "loom", -] +checksum = "66bb12751a83493ef4b8da1120451a262554e216a247f14b48cb5e8fe7ed8bdf" [[package]] name = "camino" @@ -511,19 +499,6 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" -[[package]] -name = "generator" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" -dependencies = [ - "cfg-if", - "libc", - "log", - "rustversion", - "windows 0.58.0", -] - [[package]] name = "getrandom" version = "0.2.15" @@ -1213,19 +1188,6 @@ version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" -[[package]] -name = "loom" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "tracing", - "tracing-subscriber", -] - [[package]] name = "lsp-server" version = "0.7.8" @@ -1265,15 +1227,6 @@ dependencies = [ "url", ] -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - [[package]] name = "mbe" version = "0.0.0" @@ -1400,16 +1353,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d" -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - [[package]] name = "nu-ansi-term" version = "0.50.1" @@ -1471,12 +1414,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "parking_lot" version = "0.12.3" @@ -1648,7 +1585,7 @@ dependencies = [ "indexmap", "nix", "tracing", - "windows 0.61.1", + "windows", ] [[package]] @@ -1864,50 +1801,6 @@ dependencies = [ "thiserror 2.0.12", ] -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.5", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - [[package]] name = "rowan" version = "0.15.15" @@ -2026,12 +1919,6 @@ dependencies = [ "smallvec", ] -[[package]] -name = "rustversion" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" - [[package]] name = "ryu" version = "1.0.20" @@ -2040,9 +1927,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "salsa" -version = "0.21.1" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f80d5cf3c3fcab2cef898012f242a670477a1baa609267376af9cb4409026c5" +checksum = "c8fff508e3d6ef42a32607f7538e17171a877a12015e32036f46e99d00c95781" dependencies = [ "boxcar", "crossbeam-queue", @@ -2063,15 +1950,15 @@ dependencies = [ [[package]] name = "salsa-macro-rules" -version = "0.21.1" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05303d72606fbf2b9c9523cda2039bb8ecb00304027a3cd7e52b02a65c7d9185" +checksum = "8ea72b3c06f2ce6350fe3a0eeb7aaaf842d1d8352b706973c19c4f02e298a87c" [[package]] name = "salsa-macros" -version = "0.21.1" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb2f0e2a30c65cb3cd63440c491dde68d9af7e1be2b77832ac7057141107db50" +checksum = "0ce92025bc160b27814a207cb78d680973af17f863c7f4fc56cf3a535e22f378" dependencies = [ "heck", "proc-macro2", @@ -2556,15 +2443,9 @@ version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ - "matchers", - "nu-ansi-term 0.46.0", - "once_cell", - "regex", "sharded-slab", - "smallvec", "thread_local", "time", - "tracing", "tracing-core", "tracing-log", ] @@ -2575,7 +2456,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f459ca79f1b0d5f71c54ddfde6debfc59c8b6eeb46808ae492077f739dc7b49c" dependencies = [ - "nu-ansi-term 0.50.1", + "nu-ansi-term", "tracing-core", "tracing-log", "tracing-subscriber", @@ -2709,22 +2590,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - [[package]] name = "winapi-util" version = "0.1.9" @@ -2734,22 +2599,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" -dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows" version = "0.61.1" @@ -2757,7 +2606,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" dependencies = [ "windows-collections", - "windows-core 0.61.0", + "windows-core", "windows-future", "windows-link", "windows-numerics", @@ -2769,20 +2618,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-core 0.61.0", -] - -[[package]] -name = "windows-core" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" -dependencies = [ - "windows-implement 0.58.0", - "windows-interface 0.58.0", - "windows-result 0.2.0", - "windows-strings 0.1.0", - "windows-targets 0.52.6", + "windows-core", ] [[package]] @@ -2791,11 +2627,11 @@ version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" dependencies = [ - "windows-implement 0.60.0", - "windows-interface 0.59.1", + "windows-implement", + "windows-interface", "windows-link", - "windows-result 0.3.2", - "windows-strings 0.4.0", + "windows-result", + "windows-strings", ] [[package]] @@ -2804,21 +2640,10 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32" dependencies = [ - "windows-core 0.61.0", + "windows-core", "windows-link", ] -[[package]] -name = "windows-implement" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-implement" version = "0.60.0" @@ -2830,17 +2655,6 @@ dependencies = [ "syn", ] -[[package]] -name = "windows-interface" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "windows-interface" version = "0.59.1" @@ -2864,19 +2678,10 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-core 0.61.0", + "windows-core", "windows-link", ] -[[package]] -name = "windows-result" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-result" version = "0.3.2" @@ -2886,16 +2691,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows-strings" version = "0.4.0" diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 07731bae3f30..8c5071898466 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -132,11 +132,8 @@ pulldown-cmark-to-cmark = "10.0.4" pulldown-cmark = { version = "0.9.6", default-features = false } rayon = "1.10.0" rowan = "=0.15.15" -salsa = { version = "0.21.1", default-features = false, features = [ - "rayon", - "salsa_unstable", -] } -salsa-macros = "0.21.1" +salsa = { version = "0.22.0", default-features = false, features = ["rayon","salsa_unstable"] } +salsa-macros = "0.22.0" semver = "1.0.26" serde = { version = "1.0.219" } serde_derive = { version = "1.0.219" } diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index d42d7e5707d3..745238167bc1 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -395,21 +395,21 @@ impl BuiltDependency { pub type CratesIdMap = FxHashMap; #[salsa_macros::input] -#[derive(Debug)] +#[derive(Debug, PartialOrd, Ord)] pub struct Crate { - #[return_ref] + #[returns(ref)] pub data: BuiltCrateData, /// Crate data that is not needed for analysis. /// /// This is split into a separate field to increase incrementality. - #[return_ref] + #[returns(ref)] pub extra_data: ExtraCrateData, // This is in `Arc` because it is shared for all crates in a workspace. - #[return_ref] + #[returns(ref)] pub workspace_data: Arc, - #[return_ref] + #[returns(ref)] pub cfg_options: CfgOptions, - #[return_ref] + #[returns(ref)] pub env: Env, } diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index a67fbf75c02f..4d4e6cae0373 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -32,6 +32,7 @@ pub use vfs::{AnchoredPath, AnchoredPathBuf, FileId, VfsPath, file_set::FileSet} macro_rules! impl_intern_key { ($id:ident, $loc:ident) => { #[salsa_macros::interned(no_lifetime)] + #[derive(PartialOrd, Ord)] pub struct $id { pub loc: $loc, } @@ -165,6 +166,7 @@ impl Files { } #[salsa_macros::interned(no_lifetime, debug, constructor=from_span)] +#[derive(PartialOrd, Ord)] pub struct EditionedFileId { pub editioned_file_id: span::EditionedFileId, } @@ -356,7 +358,7 @@ fn parse(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Parse Option<&[SyntaxError]> { - #[salsa_macros::tracked(return_ref)] + #[salsa_macros::tracked(returns(ref))] fn parse_errors(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Option> { let errors = db.parse(file_id).errors(); match &*errors { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 59344641f47a..4ad44775ea14 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -85,7 +85,7 @@ impl LangItemTarget { } /// Salsa query. This will look for lang items in a specific crate. -#[salsa_macros::tracked(return_ref)] +#[salsa_macros::tracked(returns(ref))] pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option> { let _p = tracing::info_span!("crate_lang_items_query").entered(); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index d4b30a1d3e68..f337f83156a9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -381,15 +381,15 @@ mod __ { #[salsa_macros::tracked] pub(crate) struct DefMapPair<'db> { #[tracked] - #[return_ref] + #[returns(ref)] pub(crate) def_map: DefMap, - #[return_ref] + #[returns(ref)] pub(crate) local: LocalDefMap, } } pub(crate) use __::DefMapPair; -#[salsa_macros::tracked(return_ref)] +#[salsa_macros::tracked(returns(ref))] pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefMapPair<'_> { let krate = crate_id.data(db); let _p = tracing::info_span!( @@ -420,7 +420,7 @@ pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefM DefMapPair::new(db, def_map, local_def_map) } -#[salsa_macros::tracked(return_ref)] +#[salsa_macros::tracked(returns(ref))] pub fn block_def_map(db: &dyn DefDatabase, block_id: BlockId) -> DefMap { let BlockLoc { ast_id, module } = block_id.lookup(db); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs index 6c995ab6c23f..e30a5b65a1f7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs @@ -30,9 +30,18 @@ pub(crate) struct TestDB { impl Default for TestDB { fn default() -> Self { + let events = >>>>::default(); let mut this = Self { - storage: Default::default(), - events: Default::default(), + storage: salsa::Storage::new(Some(Box::new({ + let events = events.clone(); + move |event| { + let mut events = events.lock().unwrap(); + if let Some(events) = &mut *events { + events.push(event); + } + } + }))), + events, files: Default::default(), crates_map: Default::default(), }; @@ -45,15 +54,7 @@ impl Default for TestDB { } #[salsa_macros::db] -impl salsa::Database for TestDB { - fn salsa_event(&self, event: &dyn std::ops::Fn() -> salsa::Event) { - let mut events = self.events.lock().unwrap(); - if let Some(events) = &mut *events { - let event = event(); - events.push(event); - } - } -} +impl salsa::Database for TestDB {} impl fmt::Debug for TestDB { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs index 8f0d17c9dc4e..d049c678e2db 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs @@ -27,9 +27,18 @@ pub(crate) struct TestDB { impl Default for TestDB { fn default() -> Self { + let events = >>>>::default(); let mut this = Self { - storage: Default::default(), - events: Default::default(), + storage: salsa::Storage::new(Some(Box::new({ + let events = events.clone(); + move |event| { + let mut events = events.lock().unwrap(); + if let Some(events) = &mut *events { + events.push(event); + } + } + }))), + events, files: Default::default(), crates_map: Default::default(), }; @@ -103,14 +112,7 @@ impl SourceDatabase for TestDB { } #[salsa_macros::db] -impl salsa::Database for TestDB { - fn salsa_event(&self, event: &dyn std::ops::Fn() -> salsa::Event) { - let mut events = self.events.lock().unwrap(); - if let Some(events) = &mut *events { - events.push(event()); - } - } -} +impl salsa::Database for TestDB {} impl panic::RefUnwindSafe for TestDB {} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index 63cc7cde2808..c94be7e164e2 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -92,9 +92,7 @@ pub struct RootDatabase { impl std::panic::RefUnwindSafe for RootDatabase {} #[salsa_macros::db] -impl salsa::Database for RootDatabase { - fn salsa_event(&self, _event: &dyn Fn() -> salsa::Event) {} -} +impl salsa::Database for RootDatabase {} impl Drop for RootDatabase { fn drop(&mut self) { diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs index bade0c2cd6fa..71af63a0d3b8 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs @@ -1,33 +1,41 @@ use std::sync::{Arc, Mutex}; #[salsa_macros::db] -#[derive(Default, Clone)] +#[derive(Clone)] pub(crate) struct LoggerDb { storage: salsa::Storage, logger: Logger, } +impl Default for LoggerDb { + fn default() -> Self { + let logger = Logger::default(); + Self { + storage: salsa::Storage::new(Some(Box::new({ + let logger = logger.clone(); + move |event| match event.kind { + salsa::EventKind::WillExecute { .. } + | salsa::EventKind::WillCheckCancellation + | salsa::EventKind::DidValidateMemoizedValue { .. } + | salsa::EventKind::WillDiscardStaleOutput { .. } + | salsa::EventKind::DidDiscard { .. } => { + logger.logs.lock().unwrap().push(format!("salsa_event({:?})", event.kind)); + } + _ => {} + } + }))), + logger, + } + } +} + #[derive(Default, Clone)] struct Logger { logs: Arc>>, } #[salsa_macros::db] -impl salsa::Database for LoggerDb { - fn salsa_event(&self, event: &dyn Fn() -> salsa::Event) { - let event = event(); - match event.kind { - salsa::EventKind::WillExecute { .. } - | salsa::EventKind::WillCheckCancellation - | salsa::EventKind::DidValidateMemoizedValue { .. } - | salsa::EventKind::WillDiscardStaleOutput { .. } - | salsa::EventKind::DidDiscard { .. } => { - self.push_log(format!("salsa_event({:?})", event.kind)); - } - _ => {} - } - } -} +impl salsa::Database for LoggerDb {} impl LoggerDb { /// Log an event from inside a tracked function. From 947be5f4316088f44cf2db69d137fd9afbfd7723 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 17 Apr 2025 19:43:56 -0400 Subject: [PATCH 24/80] add CStr::display The implementation delegates to `::fmt`. Link: https://github.com/rust-lang/libs-team/issues/550 Link: https://github.com/rust-lang/rust/issues/139984. --- library/core/src/ffi/c_str.rs | 24 ++++++++++++++++++++++++ library/coretests/tests/ffi/cstr.rs | 6 ++++++ library/coretests/tests/lib.rs | 1 + 3 files changed, 31 insertions(+) diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index ac07c645c019..c2799fa0b5c1 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -659,6 +659,30 @@ impl CStr { // instead of doing it afterwards. str::from_utf8(self.to_bytes()) } + + /// Returns an object that implements [`Display`] for safely printing a [`CStr`] that may + /// contain non-Unicode data. + /// + /// Behaves as if `self` were first lossily converted to a `str`, with invalid UTF-8 presented + /// as the Unicode replacement character: �. + /// + /// [`Display`]: fmt::Display + /// + /// # Examples + /// + /// ``` + /// #![feature(cstr_display)] + /// + /// let cstr = c"Hello, world!"; + /// println!("{}", cstr.display()); + /// ``` + #[unstable(feature = "cstr_display", issue = "139984")] + #[must_use = "this does not display the `CStr`; \ + it returns an object that can be displayed"] + #[inline] + pub fn display(&self) -> impl fmt::Display { + crate::bstr::ByteStr::from_bytes(self.to_bytes()) + } } // `.to_bytes()` representations are compared instead of the inner `[c_char]`s, diff --git a/library/coretests/tests/ffi/cstr.rs b/library/coretests/tests/ffi/cstr.rs index 0d85b22c585a..dc34240cd99d 100644 --- a/library/coretests/tests/ffi/cstr.rs +++ b/library/coretests/tests/ffi/cstr.rs @@ -19,3 +19,9 @@ fn debug() { let s = c"abc\x01\x02\n\xE2\x80\xA6\xFF"; assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); } + +#[test] +fn display() { + let s = c"\xf0\x28\x8c\xbc"; + assert_eq!(format!("{}", s.display()), "�(��"); +} diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index b13012009815..693b14ef7620 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -23,6 +23,7 @@ #![feature(core_io_borrowed_buf)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] +#![feature(cstr_display)] #![feature(dec2flt)] #![feature(duration_constants)] #![feature(duration_constructors)] From a3bd12b88aaf32b1036cdcb2ef3efe509dbebc15 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 24 May 2025 22:12:15 +0200 Subject: [PATCH 25/80] Path::with_extension: improve examples --- library/std/src/path.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 7959c6338581..0583ee1eb327 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2743,12 +2743,27 @@ impl Path { /// /// let path = Path::new("foo.rs"); /// assert_eq!(path.with_extension("txt"), PathBuf::from("foo.txt")); + /// assert_eq!(path.with_extension(""), PathBuf::from("foo")); + /// ``` + /// + /// Handling multiple extensions: + /// + /// ``` + /// use std::path::{Path, PathBuf}; /// /// let path = Path::new("foo.tar.gz"); - /// assert_eq!(path.with_extension(""), PathBuf::from("foo.tar")); /// assert_eq!(path.with_extension("xz"), PathBuf::from("foo.tar.xz")); /// assert_eq!(path.with_extension("").with_extension("txt"), PathBuf::from("foo.txt")); /// ``` + /// + /// Adding an extension where one did not exist: + /// + /// ``` + /// use std::path::{Path, PathBuf}; + /// + /// let path = Path::new("foo"); + /// assert_eq!(path.with_extension("rs"), PathBuf::from("foo.rs")); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_extension>(&self, extension: S) -> PathBuf { self._with_extension(extension.as_ref()) From 248f4b2ad2b18ab322748cc62b3524c109206b98 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 24 May 2025 22:17:55 +0200 Subject: [PATCH 26/80] reduce clutter... too many imports --- library/std/src/path.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 0583ee1eb327..87c5d6f0438d 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2739,30 +2739,30 @@ impl Path { /// # Examples /// /// ``` - /// use std::path::{Path, PathBuf}; + /// use std::path::Path; /// /// let path = Path::new("foo.rs"); - /// assert_eq!(path.with_extension("txt"), PathBuf::from("foo.txt")); - /// assert_eq!(path.with_extension(""), PathBuf::from("foo")); + /// assert_eq!(path.with_extension("txt"), Path::new("foo.txt")); + /// assert_eq!(path.with_extension(""), Path::new("foo")); /// ``` /// /// Handling multiple extensions: /// /// ``` - /// use std::path::{Path, PathBuf}; + /// use std::path::Path; /// /// let path = Path::new("foo.tar.gz"); - /// assert_eq!(path.with_extension("xz"), PathBuf::from("foo.tar.xz")); - /// assert_eq!(path.with_extension("").with_extension("txt"), PathBuf::from("foo.txt")); + /// assert_eq!(path.with_extension("xz"), Path::new("foo.tar.xz")); + /// assert_eq!(path.with_extension("").with_extension("txt"), Path::new("foo.txt")); /// ``` /// /// Adding an extension where one did not exist: /// /// ``` - /// use std::path::{Path, PathBuf}; + /// use std::path::Path; /// /// let path = Path::new("foo"); - /// assert_eq!(path.with_extension("rs"), PathBuf::from("foo.rs")); + /// assert_eq!(path.with_extension("rs"), Path::new("foo.rs")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_extension>(&self, extension: S) -> PathBuf { From fe1808718cc83aab514a92c7129fe76e122045cf Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 25 May 2025 17:20:20 +0300 Subject: [PATCH 27/80] Fix IDE resolution of item macros It wasn't inside the source, because there was no source map. --- .../rust-analyzer/crates/hir-def/src/db.rs | 3 ++ .../crates/hir-def/src/resolver.rs | 9 ++++ .../crates/hir-expand/src/lib.rs | 2 + .../rust-analyzer/crates/hir/src/semantics.rs | 10 ++--- .../crates/hir/src/source_analyzer.rs | 41 ++++++++----------- .../crates/ide-completion/src/tests/item.rs | 38 ++++++++++++++++- 6 files changed, 74 insertions(+), 29 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index 4a9a3b12cfab..6f9340a0e4d0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -422,6 +422,7 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { let makro = &item_tree[loc.id.value]; MacroDefId { krate: loc.container.krate, + block: loc.container.block.map(|block| salsa::plumbing::AsId::as_id(&block)), kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()), local_inner: false, allow_internal_unsafe: loc.allow_internal_unsafe, @@ -435,6 +436,7 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { let makro = &item_tree[loc.id.value]; MacroDefId { krate: loc.container.krate, + block: loc.container.block.map(|block| salsa::plumbing::AsId::as_id(&block)), kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()), local_inner: loc.flags.contains(MacroRulesLocFlags::LOCAL_INNER), allow_internal_unsafe: loc @@ -450,6 +452,7 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { let makro = &item_tree[loc.id.value]; MacroDefId { krate: loc.container.krate, + block: None, kind: MacroDefKind::ProcMacro( InFile::new(loc.id.file_id(), makro.ast_id), loc.expander, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 16988ddf04b2..416bcbb096bd 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -696,6 +696,15 @@ impl<'db> Resolver<'db> { &def_map[local_id].scope } + pub fn item_scopes(&self) -> impl Iterator { + self.scopes() + .filter_map(move |scope| match scope { + Scope::BlockScope(m) => Some(&m.def_map[m.module_id].scope), + _ => None, + }) + .chain(std::iter::once(&self.module_scope.def_map[self.module_scope.module_id].scope)) + } + pub fn krate(&self) -> Crate { self.module_scope.def_map.krate() } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index d844d8f41eef..19cd0298e93d 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -258,6 +258,8 @@ pub struct MacroCallLoc { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct MacroDefId { pub krate: Crate, + // FIXME: In `hir-expand` we can't refer to `BlockId`. + pub block: Option, pub edition: Edition, pub kind: MacroDefKind, pub local_inner: bool, diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index caa6700de9f9..e479770b47e9 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -411,7 +411,7 @@ impl<'db> SemanticsImpl<'db> { let sa = self.analyze_no_infer(macro_call.syntax())?; let macro_call = InFile::new(sa.file_id, macro_call); - let file_id = sa.expand(self.db, macro_call)?; + let file_id = sa.expansion(self.db, macro_call)?; let node = self.parse_or_expand(file_id.into()); Some(node) @@ -437,7 +437,7 @@ impl<'db> SemanticsImpl<'db> { let sa = self.analyze_no_infer(macro_call.syntax())?; let macro_call = InFile::new(sa.file_id, macro_call); - let file_id = sa.expand(self.db, macro_call)?; + let file_id = sa.expansion(self.db, macro_call)?; let macro_call = self.db.lookup_intern_macro_call(file_id); let skip = matches!( @@ -576,7 +576,7 @@ impl<'db> SemanticsImpl<'db> { ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> { let analyzer = self.analyze_no_infer(actual_macro_call.syntax())?; let macro_call = InFile::new(analyzer.file_id, actual_macro_call); - let macro_file = analyzer.expansion(macro_call)?; + let macro_file = analyzer.expansion(self.db, macro_call)?; hir_expand::db::expand_speculative( self.db, macro_file, @@ -1120,7 +1120,7 @@ impl<'db> SemanticsImpl<'db> { false, ) })? - .expand(self.db, mcall.as_ref())?; + .expansion(self.db, mcall.as_ref())?; m_cache.insert(mcall, it); it } @@ -1579,7 +1579,7 @@ impl<'db> SemanticsImpl<'db> { let sa = self.analyze(macro_call.syntax())?; self.db .parse_macro_expansion( - sa.expand(self.db, self.wrap_node_infile(macro_call.clone()).as_ref())?, + sa.expansion(self.db, self.wrap_node_infile(macro_call.clone()).as_ref())?, ) .value .1 diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index ea21546f9d76..be581292152d 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -26,7 +26,7 @@ use hir_def::{ }, hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat}, lang_item::LangItem, - nameres::{MacroSubNs, crate_def_map}, + nameres::{MacroSubNs, block_def_map, crate_def_map}, resolver::{HasResolver, Resolver, TypeNs, ValueNs, resolver_for_scope}, type_ref::{Mutability, TypeRefId}, }; @@ -218,8 +218,16 @@ impl<'db> SourceAnalyzer<'db> { }) } - pub(crate) fn expansion(&self, node: InFile<&ast::MacroCall>) -> Option { - self.store_sm()?.expansion(node) + pub(crate) fn expansion( + &self, + db: &dyn HirDatabase, + macro_call: InFile<&ast::MacroCall>, + ) -> Option { + self.store_sm().and_then(|sm| sm.expansion(macro_call)).or_else(|| { + let ast_id_map = db.ast_id_map(macro_call.file_id); + let call_ast_id = macro_call.with_value(ast_id_map.ast_id(macro_call.value)); + self.resolver.item_scopes().find_map(|scope| scope.macro_invoc(call_ast_id)) + }) } fn trait_environment(&self, db: &'db dyn HirDatabase) -> Arc { @@ -747,17 +755,16 @@ impl<'db> SourceAnalyzer<'db> { pub(crate) fn resolve_macro_call( &self, - db: &'db dyn HirDatabase, + db: &dyn HirDatabase, macro_call: InFile<&ast::MacroCall>, ) -> Option { - let bs = self.store_sm()?; - bs.expansion(macro_call).and_then(|it| { - // FIXME: Block def maps + self.expansion(db, macro_call).and_then(|it| { let def = it.lookup(db).def; - crate_def_map(db, def.krate) - .macro_def_to_macro_id - .get(&def.kind.erased_ast_id()) - .map(|it| (*it).into()) + let def_map = match def.block { + Some(block) => block_def_map(db, base_db::salsa::plumbing::FromId::from_id(block)), + None => crate_def_map(db, def.krate), + }; + def_map.macro_def_to_macro_id.get(&def.kind.erased_ast_id()).map(|it| (*it).into()) }) } @@ -1292,18 +1299,6 @@ impl<'db> SourceAnalyzer<'db> { .collect() } - pub(crate) fn expand( - &self, - db: &'db dyn HirDatabase, - macro_call: InFile<&ast::MacroCall>, - ) -> Option { - self.store_sm().and_then(|bs| bs.expansion(macro_call)).or_else(|| { - self.resolver.item_scope().macro_invoc( - macro_call.with_value(db.ast_id_map(macro_call.file_id).ast_id(macro_call.value)), - ) - }) - } - pub(crate) fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option { let infer = self.infer()?; let expr_id = self.expr_id(record_lit.into())?; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs index 55689034fb47..ed87b339fedf 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs @@ -4,7 +4,7 @@ //! in [crate::completions::mod_]. use expect_test::expect; -use crate::tests::{check_edit, check_with_base_items}; +use crate::tests::{check, check_edit, check_with_base_items}; #[test] fn target_type_or_trait_in_impl_block() { @@ -308,3 +308,39 @@ fn bar() { "#]], ); } + +#[test] +fn expression_in_item_macro() { + check( + r#" +fn foo() -> u8 { 0 } + +macro_rules! foo { + ($expr:expr) => { + const BAR: u8 = $expr; + }; +} + +foo!(f$0); + "#, + expect![[r#" + ct BAR u8 + fn foo() fn() -> u8 + ma foo!(…) macro_rules! foo + bt u32 u32 + kw const + kw crate:: + kw false + kw for + kw if + kw if let + kw loop + kw match + kw self:: + kw true + kw unsafe + kw while + kw while let + "#]], + ); +} From 753c62c8899abe05abcb7bc3cde8535f925e35bb Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 25 May 2025 20:15:58 +0300 Subject: [PATCH 28/80] Properly implement `might_be_inside_macro_call()` using semantic information instead of syntactical hacks And rename it to `is_inside_macro_call()` accordingly. --- .../rust-analyzer/crates/hir/src/semantics.rs | 72 ++++++++----------- .../crates/ide-completion/src/context.rs | 6 +- .../ide-completion/src/context/analysis.rs | 33 +++++---- .../ide-completion/src/tests/expression.rs | 50 +++++++++++++ .../rust-analyzer/crates/ide-db/src/search.rs | 34 +++++---- .../rust-analyzer/crates/ide-ssr/src/lib.rs | 2 +- .../crates/ide-ssr/src/search.rs | 2 +- .../crates/ide/src/expand_macro.rs | 9 +-- .../crates/ide/src/highlight_related.rs | 2 +- 9 files changed, 125 insertions(+), 85 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index caa6700de9f9..d855b6aab8a8 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -407,14 +407,14 @@ impl<'db> SemanticsImpl<'db> { res } - pub fn expand_macro_call(&self, macro_call: &ast::MacroCall) -> Option { + pub fn expand_macro_call(&self, macro_call: &ast::MacroCall) -> Option> { let sa = self.analyze_no_infer(macro_call.syntax())?; let macro_call = InFile::new(sa.file_id, macro_call); let file_id = sa.expand(self.db, macro_call)?; let node = self.parse_or_expand(file_id.into()); - Some(node) + Some(InFile::new(file_id.into(), node)) } pub fn check_cfg_attr(&self, attr: &ast::TokenTree) -> Option { @@ -468,10 +468,10 @@ impl<'db> SemanticsImpl<'db> { } /// If `item` has an attribute macro attached to it, expands it. - pub fn expand_attr_macro(&self, item: &ast::Item) -> Option> { + pub fn expand_attr_macro(&self, item: &ast::Item) -> Option>> { let src = self.wrap_node_infile(item.clone()); let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src.as_ref()))?; - Some(self.expand(macro_call_id)) + Some(self.expand(macro_call_id).map(|it| InFile::new(macro_call_id.into(), it))) } pub fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Attr) -> Option { @@ -846,49 +846,35 @@ impl<'db> SemanticsImpl<'db> { res } - // FIXME: This isn't quite right wrt to inner attributes - /// Does a syntactic traversal to check whether this token might be inside a macro call - pub fn might_be_inside_macro_call(&self, token: &SyntaxToken) -> bool { - token.parent_ancestors().any(|ancestor| { + pub fn is_inside_macro_call(&self, token: InFile<&SyntaxToken>) -> bool { + // FIXME: Maybe `ancestors_with_macros()` is more suitable here? Currently + // this is only used on real (not macro) files so this is not a problem. + token.value.parent_ancestors().any(|ancestor| { if ast::MacroCall::can_cast(ancestor.kind()) { return true; } - // Check if it is an item (only items can have macro attributes) that has a non-builtin attribute. - let Some(item) = ast::Item::cast(ancestor) else { return false }; - item.attrs().any(|attr| { - let Some(meta) = attr.meta() else { return false }; - let Some(path) = meta.path() else { return false }; - if let Some(attr_name) = path.as_single_name_ref() { - let attr_name = attr_name.text(); - let attr_name = Symbol::intern(attr_name.as_str()); - if attr_name == sym::derive { - return true; - } - // We ignore `#[test]` and friends in the def map, so we cannot expand them. - // FIXME: We match by text. This is both hacky and incorrect (people can, and do, create - // other macros named `test`). We cannot fix that unfortunately because we use this method - // for speculative expansion in completion, which we cannot analyze. Fortunately, most macros - // named `test` are test-like, meaning their expansion is not terribly important for IDE. - if attr_name == sym::test - || attr_name == sym::bench - || attr_name == sym::test_case - || find_builtin_attr_idx(&attr_name).is_some() - { - return false; - } + + let Some(item) = ast::Item::cast(ancestor) else { + return false; + }; + // Optimization to skip the semantic check. + if item.attrs().all(|attr| { + attr.simple_name() + .is_some_and(|attr| find_builtin_attr_idx(&Symbol::intern(&attr)).is_some()) + }) { + return false; + } + self.with_ctx(|ctx| { + if ctx.item_to_macro_call(token.with_value(&item)).is_some() { + return true; } - let mut segments = path.segments(); - let mut next_segment_text = || segments.next().and_then(|it| it.name_ref()); - // `#[core::prelude::rust_2024::test]` or `#[std::prelude::rust_2024::test]`. - if next_segment_text().is_some_and(|it| matches!(&*it.text(), "core" | "std")) - && next_segment_text().is_some_and(|it| it.text() == "prelude") - && next_segment_text().is_some() - && next_segment_text() - .is_some_and(|it| matches!(&*it.text(), "test" | "bench" | "test_case")) - { - return false; - } - true + let adt = match item { + ast::Item::Struct(it) => it.into(), + ast::Item::Enum(it) => it.into(), + ast::Item::Union(it) => it.into(), + _ => return false, + }; + ctx.has_derives(token.with_value(&adt)) }) }) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index 3baf1f3de610..5287627790ae 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -8,8 +8,8 @@ use std::{iter, ops::ControlFlow}; use base_db::RootQueryDb as _; use hir::{ - DisplayTarget, HasAttrs, Local, ModuleDef, ModuleSource, Name, PathResolution, ScopeDef, - Semantics, SemanticsScope, Symbol, Type, TypeInfo, + DisplayTarget, HasAttrs, InFile, Local, ModuleDef, ModuleSource, Name, PathResolution, + ScopeDef, Semantics, SemanticsScope, Symbol, Type, TypeInfo, }; use ide_db::{ FilePosition, FxHashMap, FxHashSet, RootDatabase, famous_defs::FamousDefs, @@ -751,7 +751,7 @@ impl<'a> CompletionContext<'a> { original_offset, } = expand_and_analyze( &sema, - original_file.syntax().clone(), + InFile::new(editioned_file_id.into(), original_file.syntax().clone()), file_with_fake_ident.syntax().clone(), offset, &original_token, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 284876ffc885..7a2230b3e361 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -1,7 +1,7 @@ //! Module responsible for analyzing the code surrounding the cursor for completion. use std::iter; -use hir::{ExpandResult, Semantics, Type, TypeInfo, Variant}; +use hir::{ExpandResult, InFile, Semantics, Type, TypeInfo, Variant}; use ide_db::{RootDatabase, active_parameter::ActiveParameter}; use itertools::Either; use syntax::{ @@ -50,7 +50,7 @@ pub(super) struct AnalysisResult { pub(super) fn expand_and_analyze( sema: &Semantics<'_, RootDatabase>, - original_file: SyntaxNode, + original_file: InFile, speculative_file: SyntaxNode, offset: TextSize, original_token: &SyntaxToken, @@ -72,7 +72,7 @@ pub(super) fn expand_and_analyze( relative_offset, ) .unwrap_or(ExpansionResult { - original_file, + original_file: original_file.value, speculative_file, original_offset: offset, speculative_offset: fake_ident_token.text_range().start(), @@ -125,7 +125,7 @@ fn token_at_offset_ignore_whitespace(file: &SyntaxNode, offset: TextSize) -> Opt /// the best we can do. fn expand_maybe_stop( sema: &Semantics<'_, RootDatabase>, - original_file: SyntaxNode, + original_file: InFile, speculative_file: SyntaxNode, original_offset: TextSize, fake_ident_token: SyntaxToken, @@ -142,17 +142,16 @@ fn expand_maybe_stop( return result; } - // This needs to come after the recursive call, because our "inside macro" detection is subtly wrong - // with regard to attribute macros named `test` that are not std's test. So hopefully we will expand - // them successfully above and be able to analyze. - // Left biased since there may already be an identifier token there, and we appended to it. - if !sema.might_be_inside_macro_call(&fake_ident_token) - && token_at_offset_ignore_whitespace(&original_file, original_offset + relative_offset) - .is_some_and(|original_token| !sema.might_be_inside_macro_call(&original_token)) + // We can't check whether the fake expansion is inside macro call, because that requires semantic info. + // But hopefully checking just the real one should be enough. + if token_at_offset_ignore_whitespace(&original_file.value, original_offset + relative_offset) + .is_some_and(|original_token| { + !sema.is_inside_macro_call(original_file.with_value(&original_token)) + }) { // Recursion base case. Some(ExpansionResult { - original_file, + original_file: original_file.value, speculative_file, original_offset, speculative_offset: fake_ident_token.text_range().start(), @@ -166,7 +165,7 @@ fn expand_maybe_stop( fn expand( sema: &Semantics<'_, RootDatabase>, - original_file: SyntaxNode, + original_file: InFile, speculative_file: SyntaxNode, original_offset: TextSize, fake_ident_token: SyntaxToken, @@ -176,7 +175,7 @@ fn expand( let parent_item = |item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast); - let original_node = token_at_offset_ignore_whitespace(&original_file, original_offset) + let original_node = token_at_offset_ignore_whitespace(&original_file.value, original_offset) .and_then(|token| token.parent_ancestors().find_map(ast::Item::cast)); let ancestor_items = iter::successors( Option::zip( @@ -249,7 +248,7 @@ fn expand( } // No attributes have been expanded, so look for macro_call! token trees or derive token trees - let orig_tt = ancestors_at_offset(&original_file, original_offset) + let orig_tt = ancestors_at_offset(&original_file.value, original_offset) .map_while(Either::::cast) .last()?; let spec_tt = ancestors_at_offset(&speculative_file, fake_ident_token.text_range().start()) @@ -292,7 +291,7 @@ fn expand( fake_mapped_tokens.into_iter().min_by_key(|(_, rank)| *rank) { return Some(ExpansionResult { - original_file, + original_file: original_file.value, speculative_file, original_offset, speculative_offset: fake_ident_token.text_range().start(), @@ -349,7 +348,7 @@ fn expand( } let result = expand_maybe_stop( sema, - actual_expansion.clone(), + InFile::new(file.into(), actual_expansion.clone()), fake_expansion.clone(), new_offset, fake_mapped_token, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index e5467767d42c..b46e4c32061b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -2111,6 +2111,56 @@ fn foo() { ); } +#[test] +fn cfg_attr_attr_macro() { + check( + r#" +//- proc_macros: identity +#[cfg_attr(test, proc_macros::identity)] +fn foo() { + $0 +} + "#, + expect![[r#" + fn foo() fn() + md proc_macros + bt u32 u32 + kw async + kw const + kw crate:: + kw enum + kw extern + kw false + kw fn + kw for + kw if + kw if let + kw impl + kw impl for + kw let + kw letm + kw loop + kw match + kw mod + kw return + kw self:: + kw static + kw struct + kw trait + kw true + kw type + kw union + kw unsafe + kw use + kw while + kw while let + sn macro_rules + sn pd + sn ppd + "#]], + ); +} + #[test] fn escaped_label() { check( diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs index 30be5bc21b49..d4ab75929279 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -524,6 +524,7 @@ impl<'a> FindUsages<'a> { fn find_nodes<'b>( sema: &'b Semantics<'_, RootDatabase>, name: &str, + file_id: EditionedFileId, node: &syntax::SyntaxNode, offset: TextSize, ) -> impl Iterator + 'b { @@ -534,7 +535,7 @@ impl<'a> FindUsages<'a> { }) .into_iter() .flat_map(move |token| { - if sema.might_be_inside_macro_call(&token) { + if sema.is_inside_macro_call(InFile::new(file_id.into(), &token)) { sema.descend_into_macros_exact(token) } else { <_>::from([token]) @@ -654,11 +655,14 @@ impl<'a> FindUsages<'a> { let tree = LazyCell::new(move || sema.parse(file_id).syntax().clone()); for offset in FindUsages::match_indices(&file_text, &finder, search_range) { - let usages = - FindUsages::find_nodes(sema, ¤t_to_process, &tree, offset) - .filter(|it| { - matches!(it.kind(), SyntaxKind::NAME | SyntaxKind::NAME_REF) - }); + let usages = FindUsages::find_nodes( + sema, + ¤t_to_process, + file_id, + &tree, + offset, + ) + .filter(|it| matches!(it.kind(), SyntaxKind::NAME | SyntaxKind::NAME_REF)); for usage in usages { if let Some(alias) = usage.parent().and_then(|it| { let path = ast::PathSegment::cast(it)?.parent_path(); @@ -813,7 +817,7 @@ impl<'a> FindUsages<'a> { let tree = LazyCell::new(move || this.sema.parse(file_id).syntax().clone()); for offset in FindUsages::match_indices(&file_text, finder, search_range) { - let usages = FindUsages::find_nodes(this.sema, name, &tree, offset) + let usages = FindUsages::find_nodes(this.sema, name, file_id, &tree, offset) .filter_map(ast::NameRef::cast); for usage in usages { let found_usage = usage @@ -970,8 +974,8 @@ impl<'a> FindUsages<'a> { return; } - for name in - Self::find_nodes(sema, name, &tree, offset).filter_map(ast::NameLike::cast) + for name in Self::find_nodes(sema, name, file_id, &tree, offset) + .filter_map(ast::NameLike::cast) { if match name { ast::NameLike::NameRef(name_ref) => self.found_name_ref(&name_ref, sink), @@ -985,8 +989,8 @@ impl<'a> FindUsages<'a> { // Search for occurrences of the `Self` referring to our type if let Some((self_ty, finder)) = &include_self_kw_refs { for offset in Self::match_indices(&text, finder, search_range) { - for name_ref in - Self::find_nodes(sema, "Self", &tree, offset).filter_map(ast::NameRef::cast) + for name_ref in Self::find_nodes(sema, "Self", file_id, &tree, offset) + .filter_map(ast::NameRef::cast) { if self.found_self_ty_name_ref(self_ty, &name_ref, sink) { return; @@ -1010,7 +1014,7 @@ impl<'a> FindUsages<'a> { let tree = LazyCell::new(move || sema.parse(file_id).syntax().clone()); for offset in Self::match_indices(&text, finder, search_range) { - for name_ref in Self::find_nodes(sema, "super", &tree, offset) + for name_ref in Self::find_nodes(sema, "super", file_id, &tree, offset) .filter_map(ast::NameRef::cast) { if self.found_name_ref(&name_ref, sink) { @@ -1020,7 +1024,7 @@ impl<'a> FindUsages<'a> { } if let Some(finder) = &is_crate_root { for offset in Self::match_indices(&text, finder, search_range) { - for name_ref in Self::find_nodes(sema, "crate", &tree, offset) + for name_ref in Self::find_nodes(sema, "crate", file_id, &tree, offset) .filter_map(ast::NameRef::cast) { if self.found_name_ref(&name_ref, sink) { @@ -1064,8 +1068,8 @@ impl<'a> FindUsages<'a> { let finder = &Finder::new("self"); for offset in Self::match_indices(&text, finder, search_range) { - for name_ref in - Self::find_nodes(sema, "self", &tree, offset).filter_map(ast::NameRef::cast) + for name_ref in Self::find_nodes(sema, "self", file_id, &tree, offset) + .filter_map(ast::NameRef::cast) { if self.found_self_module_name_ref(&name_ref, sink) { return; diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs index 339c199ec29a..43c56ac8bec5 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs @@ -287,7 +287,7 @@ impl<'db> MatchFinder<'db> { if let Some(expanded) = self.sema.expand_macro_call(¯o_call) { if let Some(tt) = macro_call.token_tree() { self.output_debug_for_nodes_at_range( - &expanded, + &expanded.value, range, &Some(self.sema.original_range(tt.syntax())), out, diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs index d89911fca403..9afbedbb1ab4 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs @@ -194,7 +194,7 @@ impl MatchFinder<'_> { // nodes that originated entirely from within the token tree of the macro call. // i.e. we don't want to match something that came from the macro itself. if let Some(range) = self.sema.original_range_opt(tt.syntax()) { - self.slow_scan_node(&expanded, rule, &Some(range), matches_out); + self.slow_scan_node(&expanded.value, rule, &Some(range), matches_out); } } } diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs index 241a702038da..9beed2cac134 100644 --- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs +++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs @@ -146,10 +146,11 @@ fn expand_macro_recur( offset_in_original_node: TextSize, ) -> Option { let ExpandResult { value: expanded, err } = match macro_call { - item @ ast::Item::MacroCall(macro_call) => { - sema.expand_attr_macro(item).or_else(|| sema.expand_allowed_builtins(macro_call))? - } - item => sema.expand_attr_macro(item)?, + item @ ast::Item::MacroCall(macro_call) => sema + .expand_attr_macro(item) + .map(|it| it.map(|it| it.value)) + .or_else(|| sema.expand_allowed_builtins(macro_call))?, + item => sema.expand_attr_macro(item)?.map(|it| it.value), }; let expanded = expanded.clone_for_update(); if let Some(err) = err { diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index fb8dbcfc7354..520ba39a238b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -653,7 +653,7 @@ impl<'a> WalkExpandedExprCtx<'a> { expr.macro_call().and_then(|call| self.sema.expand_macro_call(&call)) { match_ast! { - match expanded { + match (expanded.value) { ast::MacroStmts(it) => { self.handle_expanded(it, cb); }, From 1e9e17704adfc6bd6b01a0031b73fbc1682a0f1f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 21 May 2025 15:34:15 +0000 Subject: [PATCH 29/80] Move some code around in codegen_call_terminator --- compiler/rustc_codegen_ssa/src/mir/block.rs | 202 ++++++++++---------- 1 file changed, 103 insertions(+), 99 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 922b8a5824be..de827a475c41 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -8,7 +8,7 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::mir::{self, AssertKind, InlineAsmMacro, SwitchTargets, UnwindTerminateReason}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; -use rustc_middle::ty::{self, Instance, Ty}; +use rustc_middle::ty::{self, Instance, List, Ty}; use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; use rustc_span::source_map::Spanned; @@ -827,7 +827,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { helper: &TerminatorCodegenHelper<'tcx>, bx: &mut Bx, intrinsic: ty::IntrinsicDef, - instance: Option>, + instance: Instance<'tcx>, source_info: mir::SourceInfo, target: Option, unwind: mir::UnwindAction, @@ -837,7 +837,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // These are intrinsics that compile to panics so that we can get a message // which mentions the offending type, even from a const context. if let Some(requirement) = ValidityRequirement::from_intrinsic(intrinsic.name) { - let ty = instance.unwrap().args.type_at(0); + let ty = instance.args.type_at(0); let do_panic = !bx .tcx() @@ -910,35 +910,116 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let callee = self.codegen_operand(bx, func); let (instance, mut llfn) = match *callee.layout.ty.kind() { - ty::FnDef(def_id, args) => ( - Some(ty::Instance::expect_resolve( + ty::FnDef(def_id, generic_args) => { + let instance = ty::Instance::expect_resolve( bx.tcx(), bx.typing_env(), def_id, - args, + generic_args, fn_span, - )), - None, - ), + ); + + let instance = match instance.def { + // We don't need AsyncDropGlueCtorShim here because it is not `noop func`, + // it is `func returning noop future` + ty::InstanceKind::DropGlue(_, None) => { + // Empty drop glue; a no-op. + let target = target.unwrap(); + return helper.funclet_br(self, bx, target, mergeable_succ); + } + ty::InstanceKind::Intrinsic(def_id) => { + let intrinsic = bx.tcx().intrinsic(def_id).unwrap(); + if let Some(merging_succ) = self.codegen_panic_intrinsic( + &helper, + bx, + intrinsic, + instance, + source_info, + target, + unwind, + mergeable_succ, + ) { + return merging_succ; + } + + let fn_abi = bx.fn_abi_of_instance(instance, List::empty()); + + let mut llargs = Vec::with_capacity(1); + let ret_dest = self.make_return_dest( + bx, + destination, + &fn_abi.ret, + &mut llargs, + Some(intrinsic), + ); + let dest = match ret_dest { + _ if fn_abi.ret.is_indirect() => llargs[0], + ReturnDest::Nothing => bx.const_undef(bx.type_ptr()), + ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => { + dst.val.llval + } + ReturnDest::DirectOperand(_) => { + bug!("Cannot use direct operand with an intrinsic call") + } + }; + + let args: Vec<_> = + args.iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect(); + + if matches!(intrinsic, ty::IntrinsicDef { name: sym::caller_location, .. }) + { + let location = self.get_caller_location( + bx, + mir::SourceInfo { span: fn_span, ..source_info }, + ); + + assert_eq!(llargs, []); + if let ReturnDest::IndirectOperand(tmp, _) = ret_dest { + location.val.store(bx, tmp); + } + self.store_return(bx, ret_dest, &fn_abi.ret, location.immediate()); + return helper.funclet_br(self, bx, target.unwrap(), mergeable_succ); + } + + match Self::codegen_intrinsic_call(bx, instance, fn_abi, &args, dest, span) + { + Ok(()) => { + if let ReturnDest::IndirectOperand(dst, _) = ret_dest { + self.store_return(bx, ret_dest, &fn_abi.ret, dst.val.llval); + } + + return if let Some(target) = target { + helper.funclet_br(self, bx, target, mergeable_succ) + } else { + bx.unreachable(); + MergingSucc::False + }; + } + Err(instance) => { + if intrinsic.must_be_overridden { + span_bug!( + span, + "intrinsic {} must be overridden by codegen backend, but isn't", + intrinsic.name, + ); + } + instance + } + } + } + _ => instance, + }; + + (Some(instance), None) + } ty::FnPtr(..) => (None, Some(callee.immediate())), _ => bug!("{} is not callable", callee.layout.ty), }; - let def = instance.map(|i| i.def); - - // We don't need AsyncDropGlueCtorShim here because it is not `noop func`, - // it is `func returning noop future` - if let Some(ty::InstanceKind::DropGlue(_, None)) = def { - // Empty drop glue; a no-op. - let target = target.unwrap(); - return helper.funclet_br(self, bx, target, mergeable_succ); - } - // FIXME(eddyb) avoid computing this if possible, when `instance` is // available - right now `sig` is only needed for getting the `abi` // and figuring out how many extra args were passed to a C-variadic `fn`. let sig = callee.layout.ty.fn_sig(bx.tcx()); - let abi = sig.abi(); let extra_args = &args[sig.inputs().skip_binder().len()..]; let extra_args = bx.tcx().mk_type_list_from_iter(extra_args.iter().map(|op_arg| { @@ -954,83 +1035,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // The arguments we'll be passing. Plus one to account for outptr, if used. let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize; - let instance = match def { - Some(ty::InstanceKind::Intrinsic(def_id)) => { - let intrinsic = bx.tcx().intrinsic(def_id).unwrap(); - if let Some(merging_succ) = self.codegen_panic_intrinsic( - &helper, - bx, - intrinsic, - instance, - source_info, - target, - unwind, - mergeable_succ, - ) { - return merging_succ; - } - - let mut llargs = Vec::with_capacity(1); - let ret_dest = self.make_return_dest( - bx, - destination, - &fn_abi.ret, - &mut llargs, - Some(intrinsic), - ); - let dest = match ret_dest { - _ if fn_abi.ret.is_indirect() => llargs[0], - ReturnDest::Nothing => bx.const_undef(bx.type_ptr()), - ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => dst.val.llval, - ReturnDest::DirectOperand(_) => { - bug!("Cannot use direct operand with an intrinsic call") - } - }; - - let args: Vec<_> = - args.iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect(); - - if matches!(intrinsic, ty::IntrinsicDef { name: sym::caller_location, .. }) { - let location = self - .get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info }); - - assert_eq!(llargs, []); - if let ReturnDest::IndirectOperand(tmp, _) = ret_dest { - location.val.store(bx, tmp); - } - self.store_return(bx, ret_dest, &fn_abi.ret, location.immediate()); - return helper.funclet_br(self, bx, target.unwrap(), mergeable_succ); - } - - let instance = *instance.as_ref().unwrap(); - match Self::codegen_intrinsic_call(bx, instance, fn_abi, &args, dest, span) { - Ok(()) => { - if let ReturnDest::IndirectOperand(dst, _) = ret_dest { - self.store_return(bx, ret_dest, &fn_abi.ret, dst.val.llval); - } - - return if let Some(target) = target { - helper.funclet_br(self, bx, target, mergeable_succ) - } else { - bx.unreachable(); - MergingSucc::False - }; - } - Err(instance) => { - if intrinsic.must_be_overridden { - span_bug!( - span, - "intrinsic {} must be overridden by codegen backend, but isn't", - intrinsic.name, - ); - } - Some(instance) - } - } - } - _ => instance, - }; - let mut llargs = Vec::with_capacity(arg_count); // We still need to call `make_return_dest` even if there's no `target`, since @@ -1040,7 +1044,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let destination = target.map(|target| (return_dest, target)); // Split the rust-call tupled arguments off. - let (first_args, untuple) = if abi == ExternAbi::RustCall + let (first_args, untuple) = if sig.abi() == ExternAbi::RustCall && let Some((tup, args)) = args.split_last() { (args, Some(tup)) @@ -1055,7 +1059,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { 'make_args: for (i, arg) in first_args.iter().enumerate() { let mut op = self.codegen_operand(bx, &arg.node); - if let (0, Some(ty::InstanceKind::Virtual(_, idx))) = (i, def) { + if let (0, Some(ty::InstanceKind::Virtual(_, idx))) = (i, instance.map(|i| i.def)) { match op.val { Pair(data_ptr, meta) => { // In the case of Rc, we need to explicitly pass a From e4700e76d83428a99f2c7a8b19d3bf50606cf7e1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 22 May 2025 11:17:51 +0000 Subject: [PATCH 30/80] Always use fn_span in codegen_call_terminator --- compiler/rustc_codegen_ssa/src/mir/block.rs | 26 +++++++++------------ 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index de827a475c41..beb13ba28bc3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -903,8 +903,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn_span: Span, mergeable_succ: bool, ) -> MergingSucc { - let source_info = terminator.source_info; - let span = source_info.span; + let source_info = mir::SourceInfo { span: fn_span, ..terminator.source_info }; // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. let callee = self.codegen_operand(bx, func); @@ -968,10 +967,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if matches!(intrinsic, ty::IntrinsicDef { name: sym::caller_location, .. }) { - let location = self.get_caller_location( - bx, - mir::SourceInfo { span: fn_span, ..source_info }, - ); + let location = self.get_caller_location(bx, source_info); assert_eq!(llargs, []); if let ReturnDest::IndirectOperand(tmp, _) = ret_dest { @@ -981,8 +977,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return helper.funclet_br(self, bx, target.unwrap(), mergeable_succ); } - match Self::codegen_intrinsic_call(bx, instance, fn_abi, &args, dest, span) - { + match Self::codegen_intrinsic_call( + bx, instance, fn_abi, &args, dest, fn_span, + ) { Ok(()) => { if let ReturnDest::IndirectOperand(dst, _) = ret_dest { self.store_return(bx, ret_dest, &fn_abi.ret, dst.val.llval); @@ -998,7 +995,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Err(instance) => { if intrinsic.must_be_overridden { span_bug!( - span, + fn_span, "intrinsic {} must be overridden by codegen backend, but isn't", intrinsic.name, ); @@ -1113,7 +1110,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Make sure that we've actually unwrapped the rcvr down // to a pointer or ref to `dyn* Trait`. if !op.layout.ty.builtin_deref(true).unwrap().is_dyn_star() { - span_bug!(span, "can't codegen a virtual call on {:#?}", op); + span_bug!(fn_span, "can't codegen a virtual call on {:#?}", op); } let place = op.deref(bx.cx()); let data_place = place.project_field(bx, 0); @@ -1129,7 +1126,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { continue; } _ => { - span_bug!(span, "can't codegen a virtual call on {:#?}", op); + span_bug!(fn_span, "can't codegen a virtual call on {:#?}", op); } } } @@ -1179,8 +1176,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir_args + 1, "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR: {instance:?} {fn_span:?} {fn_abi:?}", ); - let location = - self.get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info }); + let location = self.get_caller_location(bx, source_info); debug!( "codegen_call_terminator({:?}): location={:?} (fn_span {:?})", terminator, location, fn_span @@ -1199,9 +1195,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let fn_ptr = match (instance, llfn) { (Some(instance), None) => bx.get_fn_addr(instance), (_, Some(llfn)) => llfn, - _ => span_bug!(span, "no instance or llfn for call"), + _ => span_bug!(fn_span, "no instance or llfn for call"), }; - self.set_debug_loc(bx, mir::SourceInfo { span: fn_span, ..source_info }); + self.set_debug_loc(bx, source_info); helper.do_call( self, bx, From c83358beb5f40a8b1c6e422f229ca4db1f927599 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 22 May 2025 13:50:47 +0000 Subject: [PATCH 31/80] Move caller_location handling into codegen_intrinsic_call --- compiler/rustc_codegen_ssa/src/mir/block.rs | 25 +++++++------------ .../rustc_codegen_ssa/src/mir/intrinsic.rs | 13 ++++++++-- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index beb13ba28bc3..1d11b907e908 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -11,8 +11,8 @@ use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Instance, List, Ty}; use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; +use rustc_span::Span; use rustc_span::source_map::Spanned; -use rustc_span::{Span, sym}; use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; use tracing::{debug, info}; @@ -965,20 +965,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let args: Vec<_> = args.iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect(); - if matches!(intrinsic, ty::IntrinsicDef { name: sym::caller_location, .. }) - { - let location = self.get_caller_location(bx, source_info); - - assert_eq!(llargs, []); - if let ReturnDest::IndirectOperand(tmp, _) = ret_dest { - location.val.store(bx, tmp); - } - self.store_return(bx, ret_dest, &fn_abi.ret, location.immediate()); - return helper.funclet_br(self, bx, target.unwrap(), mergeable_succ); - } - - match Self::codegen_intrinsic_call( - bx, instance, fn_abi, &args, dest, fn_span, + match self.codegen_intrinsic_call( + bx, + instance, + fn_abi, + &args, + dest, + source_info, ) { Ok(()) => { if let ReturnDest::IndirectOperand(dst, _) = ret_dest { @@ -1667,7 +1660,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { tuple.layout.fields.count() } - fn get_caller_location( + pub(super) fn get_caller_location( &mut self, bx: &mut Bx, source_info: mir::SourceInfo, diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index b0fcfee2adf5..6cdd8480cbe3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -1,8 +1,9 @@ use rustc_abi::WrappingRange; +use rustc_middle::mir::SourceInfo; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; -use rustc_span::{Span, sym}; +use rustc_span::sym; use rustc_target::callconv::{FnAbi, PassMode}; use super::FunctionCx; @@ -52,13 +53,15 @@ fn memset_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { /// In the `Err` case, returns the instance that should be called instead. pub fn codegen_intrinsic_call( + &mut self, bx: &mut Bx, instance: ty::Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, Bx::Value>], llresult: Bx::Value, - span: Span, + source_info: SourceInfo, ) -> Result<(), ty::Instance<'tcx>> { + let span = source_info.span; let callee_ty = instance.ty(bx.tcx(), bx.typing_env()); let ty::FnDef(def_id, fn_args) = *callee_ty.kind() else { @@ -105,6 +108,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return Ok(()); } + sym::caller_location => { + let location = self.get_caller_location(bx, source_info); + location.val.store(bx, result); + return Ok(()); + } + sym::va_start => bx.va_start(args[0].immediate()), sym::va_end => bx.va_end(args[0].immediate()), sym::size_of_val => { From 6016f84e716c443f64c491a26f5ec1dfd42f2491 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 22 May 2025 14:15:41 +0000 Subject: [PATCH 32/80] Pass PlaceRef rather than Bx::Value to codegen_intrinsic_call --- .../rustc_codegen_gcc/src/intrinsic/mod.rs | 21 ++++---- compiler/rustc_codegen_llvm/src/intrinsic.rs | 50 ++++++++----------- compiler/rustc_codegen_ssa/src/mir/block.rs | 4 +- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 5 +- .../rustc_codegen_ssa/src/traits/intrinsic.rs | 3 +- 5 files changed, 38 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index ba65c8205a50..18dabe9ea16c 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -22,7 +22,7 @@ use rustc_codegen_ssa::traits::{ }; use rustc_middle::bug; #[cfg(feature = "master")] -use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; +use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, Instance, Ty}; use rustc_span::{Span, Symbol, sym}; @@ -202,7 +202,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc instance: Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, RValue<'gcc>>], - llresult: RValue<'gcc>, + result: PlaceRef<'tcx, RValue<'gcc>>, span: Span, ) -> Result<(), Instance<'tcx>> { let tcx = self.tcx; @@ -221,7 +221,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc let name_str = name.as_str(); let llret_ty = self.layout_of(ret_ty).gcc_type(self); - let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); let simple = get_simple_intrinsic(self, name); let simple_func = get_simple_function(self, name); @@ -271,7 +270,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc args[0].immediate(), args[1].immediate(), args[2].immediate(), - llresult, + result, ); return Ok(()); } @@ -1230,14 +1229,13 @@ fn try_intrinsic<'a, 'b, 'gcc, 'tcx>( try_func: RValue<'gcc>, data: RValue<'gcc>, _catch_func: RValue<'gcc>, - dest: RValue<'gcc>, + dest: PlaceRef<'tcx, RValue<'gcc>>, ) { if bx.sess().panic_strategy() == PanicStrategy::Abort { bx.call(bx.type_void(), None, None, try_func, &[data], None, None); // Return 0 unconditionally from the intrinsic call; // we can never unwind. - let ret_align = bx.tcx.data_layout.i32_align.abi; - bx.store(bx.const_i32(0), dest, ret_align); + OperandValue::Immediate(bx.const_i32(0)).store(bx, dest); } else { if wants_msvc_seh(bx.sess()) { unimplemented!(); @@ -1261,12 +1259,12 @@ fn try_intrinsic<'a, 'b, 'gcc, 'tcx>( // functions in play. By calling a shim we're guaranteed that our shim will have // the right personality function. #[cfg(feature = "master")] -fn codegen_gnu_try<'gcc>( - bx: &mut Builder<'_, 'gcc, '_>, +fn codegen_gnu_try<'gcc, 'tcx>( + bx: &mut Builder<'_, 'gcc, 'tcx>, try_func: RValue<'gcc>, data: RValue<'gcc>, catch_func: RValue<'gcc>, - dest: RValue<'gcc>, + dest: PlaceRef<'tcx, RValue<'gcc>>, ) { let cx: &CodegenCx<'gcc, '_> = bx.cx; let (llty, func) = get_rust_try_fn(cx, &mut |mut bx| { @@ -1322,8 +1320,7 @@ fn codegen_gnu_try<'gcc>( // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). let ret = bx.call(llty, None, None, func, &[try_func, data, catch_func], None, None); - let i32_align = bx.tcx().data_layout.i32_align.abi; - bx.store(ret, dest, i32_align); + OperandValue::Immediate(ret).store(bx, dest); } // Helper function used to get a handle to the `__rust_try` function used to diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 5ca573752922..067dd9b1681f 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -167,7 +167,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { instance: ty::Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, &'ll Value>], - llresult: &'ll Value, + result: PlaceRef<'tcx, &'ll Value>, span: Span, ) -> Result<(), ty::Instance<'tcx>> { let tcx = self.tcx; @@ -184,7 +184,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { let name = tcx.item_name(def_id); let llret_ty = self.layout_of(ret_ty).llvm_type(self); - let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); let simple = get_simple_intrinsic(self, name); let llval = match name { @@ -255,7 +254,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { args[0].immediate(), args[1].immediate(), args[2].immediate(), - llresult, + result, ); return Ok(()); } @@ -688,20 +687,19 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } } -fn catch_unwind_intrinsic<'ll>( - bx: &mut Builder<'_, 'll, '_>, +fn catch_unwind_intrinsic<'ll, 'tcx>( + bx: &mut Builder<'_, 'll, 'tcx>, try_func: &'ll Value, data: &'ll Value, catch_func: &'ll Value, - dest: &'ll Value, + dest: PlaceRef<'tcx, &'ll Value>, ) { if bx.sess().panic_strategy() == PanicStrategy::Abort { let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); bx.call(try_func_ty, None, None, try_func, &[data], None, None); // Return 0 unconditionally from the intrinsic call; // we can never unwind. - let ret_align = bx.tcx().data_layout.i32_align.abi; - bx.store(bx.const_i32(0), dest, ret_align); + OperandValue::Immediate(bx.const_i32(0)).store(bx, dest); } else if wants_msvc_seh(bx.sess()) { codegen_msvc_try(bx, try_func, data, catch_func, dest); } else if wants_wasm_eh(bx.sess()) { @@ -720,12 +718,12 @@ fn catch_unwind_intrinsic<'ll>( // instructions are meant to work for all targets, as of the time of this // writing, however, LLVM does not recommend the usage of these new instructions // as the old ones are still more optimized. -fn codegen_msvc_try<'ll>( - bx: &mut Builder<'_, 'll, '_>, +fn codegen_msvc_try<'ll, 'tcx>( + bx: &mut Builder<'_, 'll, 'tcx>, try_func: &'ll Value, data: &'ll Value, catch_func: &'ll Value, - dest: &'ll Value, + dest: PlaceRef<'tcx, &'ll Value>, ) { let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| { bx.set_personality_fn(bx.eh_personality()); @@ -865,17 +863,16 @@ fn codegen_msvc_try<'ll>( // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None); - let i32_align = bx.tcx().data_layout.i32_align.abi; - bx.store(ret, dest, i32_align); + OperandValue::Immediate(ret).store(bx, dest); } // WASM's definition of the `rust_try` function. -fn codegen_wasm_try<'ll>( - bx: &mut Builder<'_, 'll, '_>, +fn codegen_wasm_try<'ll, 'tcx>( + bx: &mut Builder<'_, 'll, 'tcx>, try_func: &'ll Value, data: &'ll Value, catch_func: &'ll Value, - dest: &'ll Value, + dest: PlaceRef<'tcx, &'ll Value>, ) { let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| { bx.set_personality_fn(bx.eh_personality()); @@ -939,8 +936,7 @@ fn codegen_wasm_try<'ll>( // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None); - let i32_align = bx.tcx().data_layout.i32_align.abi; - bx.store(ret, dest, i32_align); + OperandValue::Immediate(ret).store(bx, dest); } // Definition of the standard `try` function for Rust using the GNU-like model @@ -954,12 +950,12 @@ fn codegen_wasm_try<'ll>( // function calling it, and that function may already have other personality // functions in play. By calling a shim we're guaranteed that our shim will have // the right personality function. -fn codegen_gnu_try<'ll>( - bx: &mut Builder<'_, 'll, '_>, +fn codegen_gnu_try<'ll, 'tcx>( + bx: &mut Builder<'_, 'll, 'tcx>, try_func: &'ll Value, data: &'ll Value, catch_func: &'ll Value, - dest: &'ll Value, + dest: PlaceRef<'tcx, &'ll Value>, ) { let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| { // Codegens the shims described above: @@ -1006,19 +1002,18 @@ fn codegen_gnu_try<'ll>( // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None); - let i32_align = bx.tcx().data_layout.i32_align.abi; - bx.store(ret, dest, i32_align); + OperandValue::Immediate(ret).store(bx, dest); } // Variant of codegen_gnu_try used for emscripten where Rust panics are // implemented using C++ exceptions. Here we use exceptions of a specific type // (`struct rust_panic`) to represent Rust panics. -fn codegen_emcc_try<'ll>( - bx: &mut Builder<'_, 'll, '_>, +fn codegen_emcc_try<'ll, 'tcx>( + bx: &mut Builder<'_, 'll, 'tcx>, try_func: &'ll Value, data: &'ll Value, catch_func: &'ll Value, - dest: &'ll Value, + dest: PlaceRef<'tcx, &'ll Value>, ) { let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| { // Codegens the shims described above: @@ -1089,8 +1084,7 @@ fn codegen_emcc_try<'ll>( // Note that no invoke is used here because by definition this function // can't panic (that's what it's catching). let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None); - let i32_align = bx.tcx().data_layout.i32_align.abi; - bx.store(ret, dest, i32_align); + OperandValue::Immediate(ret).store(bx, dest); } // Helper function to give a Block to a closure to codegen a shim function. diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 1d11b907e908..1a291b17886c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -965,12 +965,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let args: Vec<_> = args.iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect(); + let result = PlaceRef::new_sized(dest, fn_abi.ret.layout); + match self.codegen_intrinsic_call( bx, instance, fn_abi, &args, - dest, + result, source_info, ) { Ok(()) => { diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 6cdd8480cbe3..6a0778832981 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -58,7 +58,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { instance: ty::Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, Bx::Value>], - llresult: Bx::Value, + result: PlaceRef<'tcx, Bx::Value>, source_info: SourceInfo, ) -> Result<(), ty::Instance<'tcx>> { let span = source_info.span; @@ -100,7 +100,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } let llret_ty = bx.backend_type(bx.layout_of(ret_ty)); - let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); let llval = match name { sym::abort => { @@ -537,7 +536,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => { // Need to use backend-specific things in the implementation. - return bx.codegen_intrinsic_call(instance, fn_abi, args, llresult, span); + return bx.codegen_intrinsic_call(instance, fn_abi, args, result, span); } }; diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs index 88cf8dbf0c5c..f9d6dab6fafc 100644 --- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs @@ -4,6 +4,7 @@ use rustc_target::callconv::FnAbi; use super::BackendTypes; use crate::mir::operand::OperandRef; +use crate::mir::place::PlaceRef; pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes { /// Remember to add all intrinsics here, in `compiler/rustc_hir_analysis/src/check/mod.rs`, @@ -16,7 +17,7 @@ pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes { instance: ty::Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, Self::Value>], - llresult: Self::Value, + result: PlaceRef<'tcx, Self::Value>, span: Span, ) -> Result<(), ty::Instance<'tcx>>; From 0a14e1b2e7483179fa74f44d3c198c33325f6d29 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 22 May 2025 14:58:58 +0000 Subject: [PATCH 33/80] Remove usage of FnAbi in codegen_intrinsic_call --- .../rustc_codegen_gcc/src/intrinsic/mod.rs | 32 +++++++------------ compiler/rustc_codegen_llvm/src/intrinsic.rs | 30 ++++++----------- compiler/rustc_codegen_ssa/src/mir/block.rs | 10 ++---- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 18 ++++------- .../rustc_codegen_ssa/src/traits/intrinsic.rs | 4 +-- 5 files changed, 31 insertions(+), 63 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 18dabe9ea16c..1bcb891a2504 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -26,7 +26,7 @@ use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, Instance, Ty}; use rustc_span::{Span, Symbol, sym}; -use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; +use rustc_target::callconv::{ArgAbi, PassMode}; use rustc_target::spec::PanicStrategy; #[cfg(feature = "master")] @@ -200,7 +200,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc fn codegen_intrinsic_call( &mut self, instance: Instance<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, RValue<'gcc>>], result: PlaceRef<'tcx, RValue<'gcc>>, span: Span, @@ -285,17 +284,10 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc } sym::volatile_load | sym::unaligned_volatile_load => { - let tp_ty = fn_args.type_at(0); let ptr = args[0].immediate(); - let layout = self.layout_of(tp_ty); - let load = if let PassMode::Cast { cast: ref ty, pad_i32: _ } = fn_abi.ret.mode { - let gcc_ty = ty.gcc_type(self); - self.volatile_load(gcc_ty, ptr) - } else { - self.volatile_load(layout.gcc_type(self), ptr) - }; + let load = self.volatile_load(result.layout.gcc_type(self), ptr); // TODO(antoyo): set alignment. - if let BackendRepr::Scalar(scalar) = layout.backend_repr { + if let BackendRepr::Scalar(scalar) = result.layout.backend_repr { self.to_immediate_scalar(load, scalar) } else { load @@ -510,16 +502,14 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc _ => return Err(Instance::new_raw(instance.def_id(), instance.args)), }; - if !fn_abi.ret.is_ignore() { - if let PassMode::Cast { cast: ref ty, .. } = fn_abi.ret.mode { - let ptr_llty = self.type_ptr_to(ty.gcc_type(self)); - let ptr = self.pointercast(result.val.llval, ptr_llty); - self.store(value, ptr, result.val.align); - } else { - OperandRef::from_immediate_or_packed_pair(self, value, result.layout) - .val - .store(self, result); - } + if result.layout.ty.is_bool() { + OperandRef::from_immediate_or_packed_pair(self, value, result.layout) + .val + .store(self, result); + } else if !result.layout.ty.is_unit() { + let ptr_llty = self.type_ptr_to(result.layout.gcc_type(self)); + let ptr = self.pointercast(result.val.llval, ptr_llty); + self.store(value, ptr, result.val.align); } Ok(()) } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 067dd9b1681f..e8629aeebb95 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -15,11 +15,10 @@ use rustc_middle::ty::{self, GenericArgsRef, Ty}; use rustc_middle::{bug, span_bug}; use rustc_span::{Span, Symbol, sym}; use rustc_symbol_mangling::mangle_internal_symbol; -use rustc_target::callconv::{FnAbi, PassMode}; use rustc_target::spec::{HasTargetSpec, PanicStrategy}; use tracing::debug; -use crate::abi::{FnAbiLlvmExt, LlvmType}; +use crate::abi::FnAbiLlvmExt; use crate::builder::Builder; use crate::context::CodegenCx; use crate::llvm::{self, Metadata}; @@ -165,7 +164,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { fn codegen_intrinsic_call( &mut self, instance: ty::Instance<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, &'ll Value>], result: PlaceRef<'tcx, &'ll Value>, span: Span, @@ -263,7 +261,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { self.call_intrinsic("llvm.va_copy", &[args[0].immediate(), args[1].immediate()]) } sym::va_arg => { - match fn_abi.ret.layout.backend_repr { + match result.layout.backend_repr { BackendRepr::Scalar(scalar) => { match scalar.primitive() { Primitive::Int(..) => { @@ -298,18 +296,12 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } sym::volatile_load | sym::unaligned_volatile_load => { - let tp_ty = fn_args.type_at(0); let ptr = args[0].immediate(); - let load = if let PassMode::Cast { cast: ty, pad_i32: _ } = &fn_abi.ret.mode { - let llty = ty.llvm_type(self); - self.volatile_load(llty, ptr) - } else { - self.volatile_load(self.layout_of(tp_ty).llvm_type(self), ptr) - }; + let load = self.volatile_load(result.layout.llvm_type(self), ptr); let align = if name == sym::unaligned_volatile_load { 1 } else { - self.align_of(tp_ty).bytes() as u32 + result.layout.align.abi.bytes() as u32 }; unsafe { llvm::LLVMSetAlignment(load, align); @@ -628,14 +620,12 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } }; - if !fn_abi.ret.is_ignore() { - if let PassMode::Cast { .. } = &fn_abi.ret.mode { - self.store(llval, result.val.llval, result.val.align); - } else { - OperandRef::from_immediate_or_packed_pair(self, llval, result.layout) - .val - .store(self, result); - } + if result.layout.ty.is_bool() { + OperandRef::from_immediate_or_packed_pair(self, llval, result.layout) + .val + .store(self, result); + } else if !result.layout.ty.is_unit() { + self.store_to_place(llval, result.val); } Ok(()) } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 1a291b17886c..a2565c4f69d3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -967,14 +967,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let result = PlaceRef::new_sized(dest, fn_abi.ret.layout); - match self.codegen_intrinsic_call( - bx, - instance, - fn_abi, - &args, - result, - source_info, - ) { + match self.codegen_intrinsic_call(bx, instance, &args, result, source_info) + { Ok(()) => { if let ReturnDest::IndirectOperand(dst, _) = ret_dest { self.store_return(bx, ret_dest, &fn_abi.ret, dst.val.llval); diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 6a0778832981..a6d159c51e13 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -4,7 +4,6 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; use rustc_span::sym; -use rustc_target::callconv::{FnAbi, PassMode}; use super::FunctionCx; use super::operand::OperandRef; @@ -56,7 +55,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &mut self, bx: &mut Bx, instance: ty::Instance<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, Bx::Value>], result: PlaceRef<'tcx, Bx::Value>, source_info: SourceInfo, @@ -536,18 +534,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => { // Need to use backend-specific things in the implementation. - return bx.codegen_intrinsic_call(instance, fn_abi, args, result, span); + return bx.codegen_intrinsic_call(instance, args, result, span); } }; - if !fn_abi.ret.is_ignore() { - if let PassMode::Cast { .. } = &fn_abi.ret.mode { - bx.store_to_place(llval, result.val); - } else { - OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout) - .val - .store(bx, result); - } + if result.layout.ty.is_bool() { + OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout) + .val + .store(bx, result); + } else if !result.layout.ty.is_unit() { + bx.store_to_place(llval, result.val); } Ok(()) } diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs index f9d6dab6fafc..a07c569a0323 100644 --- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs @@ -1,6 +1,5 @@ -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty; use rustc_span::Span; -use rustc_target::callconv::FnAbi; use super::BackendTypes; use crate::mir::operand::OperandRef; @@ -15,7 +14,6 @@ pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes { fn codegen_intrinsic_call( &mut self, instance: ty::Instance<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, Self::Value>], result: PlaceRef<'tcx, Self::Value>, span: Span, From 7122648e3403bbbd471cd2667d5960a109bb9bd7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 22 May 2025 17:49:28 +0000 Subject: [PATCH 34/80] Don't depend on FnAbi for intrinsics Intrinsics are not real functions and as such don't have any calling convention. Trying to compute a calling convention for an intrinsic anyway is a nonsensical operation. --- compiler/rustc_codegen_ssa/src/mir/block.rs | 74 ++++++++++++--------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index a2565c4f69d3..cb8088e9efba 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -8,7 +8,7 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::mir::{self, AssertKind, InlineAsmMacro, SwitchTargets, UnwindTerminateReason}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; -use rustc_middle::ty::{self, Instance, List, Ty}; +use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; use rustc_span::Span; @@ -941,37 +941,55 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return merging_succ; } - let fn_abi = bx.fn_abi_of_instance(instance, List::empty()); + let result_layout = + self.cx.layout_of(self.monomorphized_place_ty(destination.as_ref())); - let mut llargs = Vec::with_capacity(1); - let ret_dest = self.make_return_dest( - bx, - destination, - &fn_abi.ret, - &mut llargs, - Some(intrinsic), - ); - let dest = match ret_dest { - _ if fn_abi.ret.is_indirect() => llargs[0], - ReturnDest::Nothing => bx.const_undef(bx.type_ptr()), - ReturnDest::IndirectOperand(dst, _) | ReturnDest::Store(dst) => { - dst.val.llval - } - ReturnDest::DirectOperand(_) => { - bug!("Cannot use direct operand with an intrinsic call") + let (result, store_in_local) = if result_layout.is_zst() { + ( + PlaceRef::new_sized(bx.const_undef(bx.type_ptr()), result_layout), + None, + ) + } else if let Some(local) = destination.as_local() { + match self.locals[local] { + LocalRef::Place(dest) => (dest, None), + LocalRef::UnsizedPlace(_) => bug!("return type must be sized"), + LocalRef::PendingOperand => { + // Currently, intrinsics always need a location to store + // the result, so we create a temporary `alloca` for the + // result. + let tmp = PlaceRef::alloca(bx, result_layout); + tmp.storage_live(bx); + (tmp, Some(local)) + } + LocalRef::Operand(_) => { + bug!("place local already assigned to"); + } } + } else { + (self.codegen_place(bx, destination.as_ref()), None) }; + if result.val.align < result.layout.align.abi { + // Currently, MIR code generation does not create calls + // that store directly to fields of packed structs (in + // fact, the calls it creates write only to temps). + // + // If someone changes that, please update this code path + // to create a temporary. + span_bug!(self.mir.span, "can't directly store to unaligned value"); + } + let args: Vec<_> = args.iter().map(|arg| self.codegen_operand(bx, &arg.node)).collect(); - let result = PlaceRef::new_sized(dest, fn_abi.ret.layout); - match self.codegen_intrinsic_call(bx, instance, &args, result, source_info) { Ok(()) => { - if let ReturnDest::IndirectOperand(dst, _) = ret_dest { - self.store_return(bx, ret_dest, &fn_abi.ret, dst.val.llval); + if let Some(local) = store_in_local { + let op = bx.load_operand(result); + result.storage_dead(bx); + self.overwrite_local(local, LocalRef::Operand(op)); + self.debug_introduce_local(bx, local); } return if let Some(target) = target { @@ -1026,7 +1044,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // We still need to call `make_return_dest` even if there's no `target`, since // `fn_abi.ret` could be `PassMode::Indirect`, even if it is uninhabited, // and `make_return_dest` adds the return-place indirect pointer to `llargs`. - let return_dest = self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs, None); + let return_dest = self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs); let destination = target.map(|target| (return_dest, target)); // Split the rust-call tupled arguments off. @@ -1857,7 +1875,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { dest: mir::Place<'tcx>, fn_ret: &ArgAbi<'tcx, Ty<'tcx>>, llargs: &mut Vec, - intrinsic: Option, ) -> ReturnDest<'tcx, Bx::Value> { // If the return is ignored, we can just return a do-nothing `ReturnDest`. if fn_ret.is_ignore() { @@ -1877,13 +1894,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { tmp.storage_live(bx); llargs.push(tmp.val.llval); ReturnDest::IndirectOperand(tmp, index) - } else if intrinsic.is_some() { - // Currently, intrinsics always need a location to store - // the result, so we create a temporary `alloca` for the - // result. - let tmp = PlaceRef::alloca(bx, fn_ret.layout); - tmp.storage_live(bx); - ReturnDest::IndirectOperand(tmp, index) } else { ReturnDest::DirectOperand(index) }; @@ -1893,7 +1903,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } else { - self.codegen_place(bx, mir::PlaceRef { local: dest.local, projection: dest.projection }) + self.codegen_place(bx, dest.as_ref()) }; if fn_ret.is_indirect() { if dest.val.align < dest.layout.align.abi { From 165fb988499b771afb7c2ddb60f05e9e337afb6a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 23 May 2025 08:30:58 +0000 Subject: [PATCH 35/80] Reduce indentation in codegen_panic_intrinsic --- compiler/rustc_codegen_ssa/src/mir/block.rs | 94 ++++++++++----------- 1 file changed, 46 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index cb8088e9efba..1baab62ae43a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -836,58 +836,56 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Emit a panic or a no-op for `assert_*` intrinsics. // These are intrinsics that compile to panics so that we can get a message // which mentions the offending type, even from a const context. - if let Some(requirement) = ValidityRequirement::from_intrinsic(intrinsic.name) { - let ty = instance.args.type_at(0); + let Some(requirement) = ValidityRequirement::from_intrinsic(intrinsic.name) else { + return None; + }; - let do_panic = !bx - .tcx() - .check_validity_requirement((requirement, bx.typing_env().as_query_input(ty))) - .expect("expect to have layout during codegen"); + let ty = instance.args.type_at(0); - let layout = bx.layout_of(ty); + let is_valid = bx + .tcx() + .check_validity_requirement((requirement, bx.typing_env().as_query_input(ty))) + .expect("expect to have layout during codegen"); - Some(if do_panic { - let msg_str = with_no_visible_paths!({ - with_no_trimmed_paths!({ - if layout.is_uninhabited() { - // Use this error even for the other intrinsics as it is more precise. - format!("attempted to instantiate uninhabited type `{ty}`") - } else if requirement == ValidityRequirement::Zero { - format!("attempted to zero-initialize type `{ty}`, which is invalid") - } else { - format!( - "attempted to leave type `{ty}` uninitialized, which is invalid" - ) - } - }) - }); - let msg = bx.const_str(&msg_str); - - // Obtain the panic entry point. - let (fn_abi, llfn, instance) = - common::build_langcall(bx, Some(source_info.span), LangItem::PanicNounwind); - - // Codegen the actual panic invoke/call. - helper.do_call( - self, - bx, - fn_abi, - llfn, - &[msg.0, msg.1], - target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)), - unwind, - &[], - Some(instance), - mergeable_succ, - ) - } else { - // a NOP - let target = target.unwrap(); - helper.funclet_br(self, bx, target, mergeable_succ) - }) - } else { - None + if is_valid { + // a NOP + let target = target.unwrap(); + return Some(helper.funclet_br(self, bx, target, mergeable_succ)); } + + let layout = bx.layout_of(ty); + + let msg_str = with_no_visible_paths!({ + with_no_trimmed_paths!({ + if layout.is_uninhabited() { + // Use this error even for the other intrinsics as it is more precise. + format!("attempted to instantiate uninhabited type `{ty}`") + } else if requirement == ValidityRequirement::Zero { + format!("attempted to zero-initialize type `{ty}`, which is invalid") + } else { + format!("attempted to leave type `{ty}` uninitialized, which is invalid") + } + }) + }); + let msg = bx.const_str(&msg_str); + + // Obtain the panic entry point. + let (fn_abi, llfn, instance) = + common::build_langcall(bx, Some(source_info.span), LangItem::PanicNounwind); + + // Codegen the actual panic invoke/call. + Some(helper.do_call( + self, + bx, + fn_abi, + llfn, + &[msg.0, msg.1], + target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)), + unwind, + &[], + Some(instance), + mergeable_succ, + )) } fn codegen_call_terminator( From 1e7c4377de7d80786151b355307e104709904b31 Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Mon, 26 May 2025 15:37:45 +0200 Subject: [PATCH 36/80] ci: move dist-x86_64-linux job to codebuild --- src/ci/github-actions/jobs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 1d175bd97e6a..f444e09c3112 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -132,7 +132,7 @@ try: - name: dist-x86_64-linux env: CODEGEN_BACKENDS: llvm,cranelift - <<: *job-linux-16c + <<: *job-linux-36c-codebuild # Main CI jobs that have to be green to merge a commit into master # These jobs automatically inherit envs.auto, to avoid repeating @@ -228,7 +228,7 @@ auto: - name: dist-x86_64-linux env: CODEGEN_BACKENDS: llvm,cranelift - <<: *job-linux-16c + <<: *job-linux-36c-codebuild - name: dist-x86_64-linux-alt env: From 7aef56d9b938a0df077c346007921497c092fdc9 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Mon, 26 May 2025 15:06:36 -0400 Subject: [PATCH 37/80] Call out possibility of invariant result --- library/core/src/marker/variance.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/core/src/marker/variance.rs b/library/core/src/marker/variance.rs index 235f8a3bb79f..f9638fea225b 100644 --- a/library/core/src/marker/variance.rs +++ b/library/core/src/marker/variance.rs @@ -131,6 +131,8 @@ phantom_lifetime! { /// /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance /// + /// Note: If `'a` is otherwise contravariant or invariant, the resulting type is invariant. + /// /// ## Layout /// /// For all `'a`, the following are guaranteed: @@ -146,6 +148,8 @@ phantom_lifetime! { /// /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance /// + /// Note: If `'a` is otherwise covariant or invariant, the resulting type is invariant. + /// /// ## Layout /// /// For all `'a`, the following are guaranteed: @@ -180,6 +184,8 @@ phantom_type! { /// /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance /// + /// Note: If `T` is otherwise contravariant or invariant, the resulting type is invariant. + /// /// ## Layout /// /// For all `T`, the following are guaranteed: @@ -196,6 +202,8 @@ phantom_type! { /// /// [1]: https://doc.rust-lang.org/stable/reference/subtyping.html#variance /// + /// Note: If `T` is otherwise covariant or invariant, the resulting type is invariant. + /// /// ## Layout /// /// For all `T`, the following are guaranteed: From c6c2fde737e5d6730cc7135afd841a0afed6096e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelo=20Dom=C3=ADnguez?= Date: Mon, 26 May 2025 19:47:42 +0000 Subject: [PATCH 38/80] Minor macro docs fixes --- library/core/src/macros/mod.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 99a4ab52b6c5..fac1b1ae6123 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1519,8 +1519,9 @@ pub(crate) mod builtin { ($file:expr $(,)?) => {{ /* compiler built-in */ }}; } - /// the derivative of a given function in the forward mode of differentiation. - /// It may only be applied to a function. + /// This macro uses forward-mode automatic differentiation to generate a new function. + /// It may only be applied to a function. The new function will compute the derivative + /// of the function to which the macro was applied. /// /// The expected usage syntax is: /// `#[autodiff_forward(NAME, INPUT_ACTIVITIES, OUTPUT_ACTIVITY)]` @@ -1537,9 +1538,9 @@ pub(crate) mod builtin { /* compiler built-in */ } - /// Automatic Differentiation macro which allows generating a new function to compute - /// the derivative of a given function in the reverse mode of differentiation. - /// It may only be applied to a function. + /// This macro uses reverse-mode automatic differentiation to generate a new function. + /// It may only be applied to a function. The new function will compute the derivative + /// of the function to which the macro was applied. /// /// The expected usage syntax is: /// `#[autodiff_reverse(NAME, INPUT_ACTIVITIES, OUTPUT_ACTIVITY)]` From c56efaedfa0a28d842365c6c98a11af591eab1a5 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 23 May 2025 14:46:38 +0000 Subject: [PATCH 39/80] add additional `TypeFlags` fast paths --- .../src/infer/canonical/canonicalizer.rs | 4 +++ compiler/rustc_infer/src/infer/resolve.rs | 8 ++++++ compiler/rustc_middle/src/ty/erase_regions.rs | 8 ++++++ compiler/rustc_middle/src/ty/fold.rs | 4 +++ compiler/rustc_middle/src/ty/predicate.rs | 2 ++ .../rustc_middle/src/ty/structural_impls.rs | 27 ++++++++++++++++++- .../src/canonicalizer.rs | 4 +++ .../rustc_next_trait_solver/src/resolve.rs | 20 ++++++++++++-- .../src/solve/eval_ctxt/canonical.rs | 11 ++++---- .../src/solve/eval_ctxt/mod.rs | 16 +++++++++++ .../src/solve/inspect/analyse.rs | 9 +++---- compiler/rustc_type_ir/src/binder.rs | 8 ++++++ compiler/rustc_type_ir/src/fold.rs | 8 ++++++ compiler/rustc_type_ir/src/inherent.rs | 12 +++++++++ compiler/rustc_type_ir/src/interner.rs | 4 +-- compiler/rustc_type_ir/src/visit.rs | 4 +-- 16 files changed, 131 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 0b543f091f73..060447ba7206 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -497,6 +497,10 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { if p.flags().intersects(self.needs_canonical_flags) { p.super_fold_with(self) } else { p } } + + fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> { + if c.flags().intersects(self.needs_canonical_flags) { c.super_fold_with(self) } else { c } + } } impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 4b0ace8c554d..a95f24b5b95d 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -55,6 +55,14 @@ impl<'a, 'tcx> TypeFolder> for OpportunisticVarResolver<'a, 'tcx> { ct.super_fold_with(self) } } + + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if !p.has_non_region_infer() { p } else { p.super_fold_with(self) } + } + + fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> { + if !c.has_non_region_infer() { c } else { c.super_fold_with(self) } + } } /// The opportunistic region resolver opportunistically resolves regions diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index 45a0b1288db8..f4fead7e9526 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -86,4 +86,12 @@ impl<'tcx> TypeFolder> for RegionEraserVisitor<'tcx> { p } } + + fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> { + if c.has_type_flags(TypeFlags::HAS_BINDER_VARS | TypeFlags::HAS_FREE_REGIONS) { + c.super_fold_with(self) + } else { + c + } + } } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 8d6871d2f1fe..b2057fa36d7f 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -177,6 +177,10 @@ where fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } } + + fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> { + if c.has_vars_bound_at_or_above(self.current_index) { c.super_fold_with(self) } else { c } + } } impl<'tcx> TyCtxt<'tcx> { diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 551d816941b6..bc2ac42b6b1f 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -238,6 +238,8 @@ impl<'tcx> Clause<'tcx> { } } +impl<'tcx> rustc_type_ir::inherent::Clauses> for ty::Clauses<'tcx> {} + #[extension(pub trait ExistentialPredicateStableCmpExt<'tcx>)] impl<'tcx> ExistentialPredicate<'tcx> { /// Compares via an ordering that will not change if modules are reordered or other changes are diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 58f7bc75054b..def7ad6cb3a1 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -570,6 +570,19 @@ impl<'tcx> TypeFoldable> for ty::Clause<'tcx> { } } +impl<'tcx> TypeFoldable> for ty::Clauses<'tcx> { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + folder.try_fold_clauses(self) + } + + fn fold_with>>(self, folder: &mut F) -> Self { + folder.fold_clauses(self) + } +} + impl<'tcx> TypeVisitable> for ty::Predicate<'tcx> { fn visit_with>>(&self, visitor: &mut V) -> V::Result { visitor.visit_predicate(*self) @@ -615,6 +628,19 @@ impl<'tcx> TypeSuperVisitable> for ty::Clauses<'tcx> { } } +impl<'tcx> TypeSuperFoldable> for ty::Clauses<'tcx> { + fn try_super_fold_with>>( + self, + folder: &mut F, + ) -> Result { + ty::util::try_fold_list(self, folder, |tcx, v| tcx.mk_clauses(v)) + } + + fn super_fold_with>>(self, folder: &mut F) -> Self { + ty::util::fold_list(self, folder, |tcx, v| tcx.mk_clauses(v)) + } +} + impl<'tcx> TypeFoldable> for ty::Const<'tcx> { fn try_fold_with>>( self, @@ -775,7 +801,6 @@ macro_rules! list_fold { } list_fold! { - ty::Clauses<'tcx> : mk_clauses, &'tcx ty::List> : mk_poly_existential_predicates, &'tcx ty::List> : mk_place_elems, &'tcx ty::List> : mk_patterns, diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index addeb3e2b78e..1aced3f261b3 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -572,4 +572,8 @@ impl, I: Interner> TypeFolder for Canonicaliz fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { if p.flags().intersects(NEEDS_CANONICAL) { p.super_fold_with(self) } else { p } } + + fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses { + if c.flags().intersects(NEEDS_CANONICAL) { c.super_fold_with(self) } else { c } + } } diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs index 39abec2d7d8d..c3c57eccd6ef 100644 --- a/compiler/rustc_next_trait_solver/src/resolve.rs +++ b/compiler/rustc_next_trait_solver/src/resolve.rs @@ -11,7 +11,7 @@ use crate::delegate::SolverDelegate; // EAGER RESOLUTION /// Resolves ty, region, and const vars to their inferred values or their root vars. -pub struct EagerResolver<'a, D, I = ::Interner> +struct EagerResolver<'a, D, I = ::Interner> where D: SolverDelegate, I: Interner, @@ -22,8 +22,20 @@ where cache: DelayedMap, } +pub fn eager_resolve_vars>( + delegate: &D, + value: T, +) -> T { + if value.has_infer() { + let mut folder = EagerResolver::new(delegate); + value.fold_with(&mut folder) + } else { + value + } +} + impl<'a, D: SolverDelegate> EagerResolver<'a, D> { - pub fn new(delegate: &'a D) -> Self { + fn new(delegate: &'a D) -> Self { EagerResolver { delegate, cache: Default::default() } } } @@ -90,4 +102,8 @@ impl, I: Interner> TypeFolder for EagerResolv fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { if p.has_infer() { p.super_fold_with(self) } else { p } } + + fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses { + if c.has_infer() { c.super_fold_with(self) } else { c } + } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index 455a178595b2..2828b13f0362 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -22,7 +22,7 @@ use tracing::{debug, instrument, trace}; use crate::canonicalizer::Canonicalizer; use crate::delegate::SolverDelegate; -use crate::resolve::EagerResolver; +use crate::resolve::eager_resolve_vars; use crate::solve::eval_ctxt::CurrentGoalKind; use crate::solve::{ CanonicalInput, CanonicalResponse, Certainty, EvalCtxt, ExternalConstraintsData, Goal, @@ -61,8 +61,7 @@ where // so we only canonicalize the lookup table and ignore // duplicate entries. let opaque_types = self.delegate.clone_opaque_types_lookup_table(); - let (goal, opaque_types) = - (goal, opaque_types).fold_with(&mut EagerResolver::new(self.delegate)); + let (goal, opaque_types) = eager_resolve_vars(self.delegate, (goal, opaque_types)); let mut orig_values = Default::default(); let canonical = Canonicalizer::canonicalize_input( @@ -157,8 +156,8 @@ where let external_constraints = self.compute_external_query_constraints(certainty, normalization_nested_goals); - let (var_values, mut external_constraints) = (self.var_values, external_constraints) - .fold_with(&mut EagerResolver::new(self.delegate)); + let (var_values, mut external_constraints) = + eager_resolve_vars(self.delegate, (self.var_values, external_constraints)); // Remove any trivial or duplicated region constraints once we've resolved regions let mut unique = HashSet::default(); @@ -469,7 +468,7 @@ where { let var_values = CanonicalVarValues { var_values: delegate.cx().mk_args(var_values) }; let state = inspect::State { var_values, data }; - let state = state.fold_with(&mut EagerResolver::new(delegate)); + let state = eager_resolve_vars(delegate, state); Canonicalizer::canonicalize_response(delegate, max_input_universe, &mut vec![], state) } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index dfabb94ebfc6..926b5c8123a0 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -848,6 +848,22 @@ where } } } + + fn visit_predicate(&mut self, p: I::Predicate) -> Self::Result { + if p.has_non_region_infer() || p.has_placeholders() { + p.super_visit_with(self) + } else { + ControlFlow::Continue(()) + } + } + + fn visit_clauses(&mut self, c: I::Clauses) -> Self::Result { + if c.has_non_region_infer() || c.has_placeholders() { + c.super_visit_with(self) + } else { + ControlFlow::Continue(()) + } + } } let mut visitor = ContainsTermOrNotNameable { diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 9795655e8422..84808dc5b7e9 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -15,9 +15,9 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_macros::extension; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult}; -use rustc_middle::ty::{TyCtxt, TypeFoldable, VisitorResult, try_visit}; +use rustc_middle::ty::{TyCtxt, VisitorResult, try_visit}; use rustc_middle::{bug, ty}; -use rustc_next_trait_solver::resolve::EagerResolver; +use rustc_next_trait_solver::resolve::eager_resolve_vars; use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state}; use rustc_next_trait_solver::solve::{GenerateProofTree, MaybeCause, SolverDelegateEvalExt as _}; use rustc_span::{DUMMY_SP, Span}; @@ -187,8 +187,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { let _ = term_hack.constrain(infcx, span, param_env); } - let opt_impl_args = - opt_impl_args.map(|impl_args| impl_args.fold_with(&mut EagerResolver::new(infcx))); + let opt_impl_args = opt_impl_args.map(|impl_args| eager_resolve_vars(infcx, impl_args)); let goals = instantiated_goals .into_iter() @@ -392,7 +391,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { infcx, depth, orig_values, - goal: uncanonicalized_goal.fold_with(&mut EagerResolver::new(infcx)), + goal: eager_resolve_vars(infcx, uncanonicalized_goal), result, evaluation_kind: evaluation.kind, normalizes_to_term_hack, diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 000cf1e1fd8b..1b056b887dba 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -711,6 +711,14 @@ impl<'a, I: Interner> TypeFolder for ArgFolder<'a, I> { c.super_fold_with(self) } } + + fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + if p.has_param() { p.super_fold_with(self) } else { p } + } + + fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses { + if c.has_param() { c.super_fold_with(self) } else { c } + } } impl<'a, I: Interner> ArgFolder<'a, I> { diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index ce1188070ca7..a5eb8699e5fc 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -152,6 +152,10 @@ pub trait TypeFolder: Sized { fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { p.super_fold_with(self) } + + fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses { + c.super_fold_with(self) + } } /// This trait is implemented for every folding traversal. There is a fold @@ -190,6 +194,10 @@ pub trait FallibleTypeFolder: Sized { fn try_fold_predicate(&mut self, p: I::Predicate) -> Result { p.try_super_fold_with(self) } + + fn try_fold_clauses(&mut self, c: I::Clauses) -> Result { + c.try_super_fold_with(self) + } } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index ee4a8096462a..b3b49b2c6eca 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -510,6 +510,18 @@ pub trait Clause>: fn instantiate_supertrait(self, cx: I, trait_ref: ty::Binder>) -> Self; } +pub trait Clauses>: + Copy + + Debug + + Hash + + Eq + + TypeSuperVisitable + + TypeSuperFoldable + + Flags + + SliceLike +{ +} + /// Common capabilities of placeholder kinds pub trait PlaceholderLike: Copy + Debug + Hash + Eq { fn universe(self) -> ty::UniverseIndex; diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 7e88114df460..a9917192144f 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -12,7 +12,7 @@ use crate::ir_print::IrPrint; use crate::lang_items::TraitSolverLangItem; use crate::relate::Relate; use crate::solve::{CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult}; -use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; +use crate::visit::{Flags, TypeVisitable}; use crate::{self as ty, search_graph}; #[cfg_attr(feature = "nightly", rustc_diagnostic_item = "type_ir_interner")] @@ -146,7 +146,7 @@ pub trait Interner: type ParamEnv: ParamEnv; type Predicate: Predicate; type Clause: Clause; - type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable + Flags; + type Clauses: Clauses; fn with_global_cache(self, f: impl FnOnce(&mut search_graph::GlobalCache) -> R) -> R; diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index ccb84e259112..fc3864dd5ae6 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -120,8 +120,8 @@ pub trait TypeVisitor: Sized { p.super_visit_with(self) } - fn visit_clauses(&mut self, p: I::Clauses) -> Self::Result { - p.super_visit_with(self) + fn visit_clauses(&mut self, c: I::Clauses) -> Self::Result { + c.super_visit_with(self) } fn visit_error(&mut self, _guar: I::ErrorGuaranteed) -> Self::Result { From 0830ce036f92673fa54a06cc4eacb47426850d33 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 26 May 2025 11:00:29 +0000 Subject: [PATCH 40/80] assert we never incorrectly canonicalize envs --- compiler/rustc_next_trait_solver/src/canonicalizer.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 1aced3f261b3..e5ca2bda4592 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -574,6 +574,13 @@ impl, I: Interner> TypeFolder for Canonicaliz } fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses { + match self.canonicalize_mode { + CanonicalizeMode::Input { keep_static: true } + | CanonicalizeMode::Response { max_input_universe: _ } => {} + CanonicalizeMode::Input { keep_static: false } => { + panic!("erasing 'static in env") + } + } if c.flags().intersects(NEEDS_CANONICAL) { c.super_fold_with(self) } else { c } } } From 1b7a927d846ae02c3a403be0eb47714c557c49b4 Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Mon, 26 May 2025 22:27:20 +0200 Subject: [PATCH 41/80] ci: move tests from x86_64-gnu-llvm-19 job to aarch64 --- .../aarch64-gnu-llvm-19/Dockerfile | 58 +++++++++++++++++++ src/ci/docker/scripts/x86_64-gnu-llvm.sh | 4 +- src/ci/github-actions/jobs.yml | 12 +++- .../by-value-non-immediate-argument.rs | 1 + tests/run-make/mte-ffi/bar.h | 2 + tests/run-make/mte-ffi/bar_float.c | 4 +- tests/run-make/mte-ffi/bar_int.c | 2 +- tests/run-make/mte-ffi/bar_string.c | 3 +- 8 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 src/ci/docker/host-aarch64/aarch64-gnu-llvm-19/Dockerfile diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-llvm-19/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-19/Dockerfile new file mode 100644 index 000000000000..2f9d0010573a --- /dev/null +++ b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-19/Dockerfile @@ -0,0 +1,58 @@ +FROM ubuntu:24.10 + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y --no-install-recommends \ + bzip2 \ + g++ \ + make \ + ninja-build \ + file \ + curl \ + ca-certificates \ + python3 \ + git \ + cmake \ + sudo \ + gdb \ + llvm-19-tools \ + llvm-19-dev \ + libedit-dev \ + libssl-dev \ + pkg-config \ + zlib1g-dev \ + xz-utils \ + nodejs \ + mingw-w64 \ + # libgccjit dependencies + flex \ + libmpfr-dev \ + libgmp-dev \ + libmpc3 \ + libmpc-dev \ + && rm -rf /var/lib/apt/lists/* + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +# We are disabling CI LLVM since this builder is intentionally using a host +# LLVM, rather than the typical src/llvm-project LLVM. +ENV NO_DOWNLOAD_CI_LLVM 1 +ENV EXTERNAL_LLVM 1 + +# Using llvm-link-shared due to libffi issues -- see #34486 +ENV RUST_CONFIGURE_ARGS \ + --build=aarch64-unknown-linux-gnu \ + --llvm-root=/usr/lib/llvm-19 \ + --enable-llvm-link-shared \ + --set rust.randomize-layout=true \ + --set rust.thin-lto-import-instr-limit=10 + +COPY scripts/shared.sh /scripts/ + +ARG SCRIPT_ARG + +COPY scripts/stage_2_test_set1.sh /tmp/ +COPY scripts/stage_2_test_set2.sh /tmp/ + +ENV SCRIPT "/tmp/${SCRIPT_ARG}" diff --git a/src/ci/docker/scripts/x86_64-gnu-llvm.sh b/src/ci/docker/scripts/x86_64-gnu-llvm.sh index e0435a3ff5c1..5fa17d954c3b 100755 --- a/src/ci/docker/scripts/x86_64-gnu-llvm.sh +++ b/src/ci/docker/scripts/x86_64-gnu-llvm.sh @@ -2,8 +2,8 @@ set -ex -# NOTE: intentionally uses all of `x.py`, `x`, and `x.ps1` to make sure they all work on Linux. -../x.py --stage 2 test --skip src/tools/tidy +# NOTE: intentionally uses `x`, and `x.ps1` to make sure they work on Linux. +# Make sure that `x.py` is tested elsewhere. # Run the `mir-opt` tests again but this time for a 32-bit target. # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 1d175bd97e6a..d7207edb7f9b 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -121,7 +121,17 @@ pr: env: ENABLE_GCC_CODEGEN: "1" DOCKER_SCRIPT: x86_64-gnu-llvm.sh - <<: *job-linux-16c + <<: *job-linux-4c + - name: aarch64-gnu-llvm-19-1 + env: + IMAGE: aarch64-gnu-llvm-19 + DOCKER_SCRIPT: stage_2_test_set1.sh + <<: *job-aarch64-linux-8c + - name: aarch64-gnu-llvm-19-2 + env: + IMAGE: aarch64-gnu-llvm-19 + DOCKER_SCRIPT: stage_2_test_set2.sh + <<: *job-aarch64-linux - name: x86_64-gnu-tools <<: *job-linux-36c-codebuild diff --git a/tests/debuginfo/by-value-non-immediate-argument.rs b/tests/debuginfo/by-value-non-immediate-argument.rs index 192f6efe7db6..5233b95f1f4a 100644 --- a/tests/debuginfo/by-value-non-immediate-argument.rs +++ b/tests/debuginfo/by-value-non-immediate-argument.rs @@ -2,6 +2,7 @@ //@ min-gdb-version: 13.0 //@ compile-flags:-g //@ ignore-windows-gnu: #128973 +//@ ignore-aarch64-unknown-linux-gnu (gdb tries to read from 0x0; FIXME: #128973) // === GDB TESTS =================================================================================== diff --git a/tests/run-make/mte-ffi/bar.h b/tests/run-make/mte-ffi/bar.h index a2292ae02a30..9b030c618d18 100644 --- a/tests/run-make/mte-ffi/bar.h +++ b/tests/run-make/mte-ffi/bar.h @@ -1,3 +1,5 @@ +// FIXME(#141600) the mte-ffi test doesn't fail in aarch64-gnu + #ifndef __BAR_H #define __BAR_H diff --git a/tests/run-make/mte-ffi/bar_float.c b/tests/run-make/mte-ffi/bar_float.c index a1590f62765a..acc2f5d9266d 100644 --- a/tests/run-make/mte-ffi/bar_float.c +++ b/tests/run-make/mte-ffi/bar_float.c @@ -3,9 +3,9 @@ #include #include "bar.h" -extern void foo(char*); +extern void foo(float*); -void bar(char *ptr) { +void bar(float *ptr) { if (((uintptr_t)ptr >> 56) != 0x1f) { fprintf(stderr, "Top byte corrupted on Rust -> C FFI boundary!\n"); exit(1); diff --git a/tests/run-make/mte-ffi/bar_int.c b/tests/run-make/mte-ffi/bar_int.c index d1c79e95dc9c..c92e765302c1 100644 --- a/tests/run-make/mte-ffi/bar_int.c +++ b/tests/run-make/mte-ffi/bar_int.c @@ -5,7 +5,7 @@ extern void foo(unsigned int *); -void bar(char *ptr) { +void bar(unsigned int *ptr) { if (((uintptr_t)ptr >> 56) != 0x1f) { fprintf(stderr, "Top byte corrupted on Rust -> C FFI boundary!\n"); exit(1); diff --git a/tests/run-make/mte-ffi/bar_string.c b/tests/run-make/mte-ffi/bar_string.c index 5669ffd6695e..8e1202f6fd15 100644 --- a/tests/run-make/mte-ffi/bar_string.c +++ b/tests/run-make/mte-ffi/bar_string.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "bar.h" extern void foo(char*); @@ -32,7 +33,7 @@ int main(void) // Store an arbitrary tag in bits 56-59 of the pointer (where an MTE tag may be), // and a different value in the ignored top 4 bits. - ptr = (unsigned int *)((uintptr_t)ptr | 0x1fl << 56); + ptr = (char *)((uintptr_t)ptr | 0x1fl << 56); if (mte_enabled()) { set_tag(ptr); From df09feddfa7900c841877faa3cda86bfc08d9610 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 16:39:59 +1000 Subject: [PATCH 42/80] Remove `DropNodeKey::kind`. It's not needed, because `next` and `local` fields uniquely identify the drop. This is a ~2% speed win on the very large program in #134404, and it's also a tiny bit simpler. --- compiler/rustc_mir_build/src/builder/scope.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 2a30777e98c4..bc39ad6b267c 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -230,7 +230,6 @@ struct DropNode { struct DropNodeKey { next: DropIdx, local: Local, - kind: DropKind, } impl Scope { @@ -291,7 +290,7 @@ impl DropTree { let drops = &mut self.drops; *self .existing_drops_map - .entry(DropNodeKey { next, local: data.local, kind: data.kind }) + .entry(DropNodeKey { next, local: data.local }) // Create a new node, and also add its index to the map. .or_insert_with(|| drops.push(DropNode { data, next })) } From bf4532c05d2537c091de6787b8bb80e2cd24cd63 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 21 May 2025 05:46:03 +1000 Subject: [PATCH 43/80] Rename `DropTree::drops` as `DropTree::drop_nodes`. Because `Scope` also has a field named `drops`, and I found having two fields with the same name made this code harder to read. --- compiler/rustc_mir_build/src/builder/scope.rs | 80 +++++++++++-------- 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index bc39ad6b267c..d7900cb0845e 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -209,7 +209,7 @@ const ROOT_NODE: DropIdx = DropIdx::ZERO; #[derive(Debug)] struct DropTree { /// Nodes in the drop tree, containing drop data and a link to the next node. - drops: IndexVec, + drop_nodes: IndexVec, /// Map for finding the index of an existing node, given its contents. existing_drops_map: FxHashMap, /// Edges into the `DropTree` that need to be added once it's lowered. @@ -277,8 +277,8 @@ impl DropTree { let fake_source_info = SourceInfo::outermost(DUMMY_SP); let fake_data = DropData { source_info: fake_source_info, local: Local::MAX, kind: DropKind::Storage }; - let drops = IndexVec::from_raw(vec![DropNode { data: fake_data, next: DropIdx::MAX }]); - Self { drops, entry_points: Vec::new(), existing_drops_map: FxHashMap::default() } + let drop_nodes = IndexVec::from_raw(vec![DropNode { data: fake_data, next: DropIdx::MAX }]); + Self { drop_nodes, entry_points: Vec::new(), existing_drops_map: FxHashMap::default() } } /// Adds a node to the drop tree, consisting of drop data and the index of @@ -287,12 +287,12 @@ impl DropTree { /// If there is already an equivalent node in the tree, nothing is added, and /// that node's index is returned. Otherwise, the new node's index is returned. fn add_drop(&mut self, data: DropData, next: DropIdx) -> DropIdx { - let drops = &mut self.drops; + let drop_nodes = &mut self.drop_nodes; *self .existing_drops_map .entry(DropNodeKey { next, local: data.local }) // Create a new node, and also add its index to the map. - .or_insert_with(|| drops.push(DropNode { data, next })) + .or_insert_with(|| drop_nodes.push(DropNode { data, next })) } /// Registers `from` as an entry point to this drop tree, at `to`. @@ -300,7 +300,7 @@ impl DropTree { /// During [`Self::build_mir`], `from` will be linked to the corresponding /// block within the drop tree. fn add_entry_point(&mut self, from: BasicBlock, to: DropIdx) { - debug_assert!(to < self.drops.next_index()); + debug_assert!(to < self.drop_nodes.next_index()); self.entry_points.push((to, from)); } @@ -340,10 +340,10 @@ impl DropTree { Own, } - let mut blocks = IndexVec::from_elem(None, &self.drops); + let mut blocks = IndexVec::from_elem(None, &self.drop_nodes); blocks[ROOT_NODE] = root_node; - let mut needs_block = IndexVec::from_elem(Block::None, &self.drops); + let mut needs_block = IndexVec::from_elem(Block::None, &self.drop_nodes); if root_node.is_some() { // In some cases (such as drops for `continue`) the root node // already has a block. In this case, make sure that we don't @@ -355,7 +355,7 @@ impl DropTree { let entry_points = &mut self.entry_points; entry_points.sort(); - for (drop_idx, drop_node) in self.drops.iter_enumerated().rev() { + for (drop_idx, drop_node) in self.drop_nodes.iter_enumerated().rev() { if entry_points.last().is_some_and(|entry_point| entry_point.0 == drop_idx) { let block = *blocks[drop_idx].get_or_insert_with(|| T::make_block(cfg)); needs_block[drop_idx] = Block::Own; @@ -395,7 +395,7 @@ impl DropTree { cfg: &mut CFG<'tcx>, blocks: &IndexSlice>, ) { - for (drop_idx, drop_node) in self.drops.iter_enumerated().rev() { + for (drop_idx, drop_node) in self.drop_nodes.iter_enumerated().rev() { let Some(block) = blocks[drop_idx] else { continue }; match drop_node.data.kind { DropKind::Value => { @@ -828,9 +828,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // `unwind_to` should drop the value that we're about to // schedule. If dropping this value panics, then we continue // with the *next* value on the unwind path. - debug_assert_eq!(unwind_drops.drops[unwind_to].data.local, drop_data.local); - debug_assert_eq!(unwind_drops.drops[unwind_to].data.kind, drop_data.kind); - unwind_to = unwind_drops.drops[unwind_to].next; + debug_assert_eq!( + unwind_drops.drop_nodes[unwind_to].data.local, + drop_data.local + ); + debug_assert_eq!( + unwind_drops.drop_nodes[unwind_to].data.kind, + drop_data.kind + ); + unwind_to = unwind_drops.drop_nodes[unwind_to].next; let mut unwind_entry_point = unwind_to; @@ -1550,14 +1556,14 @@ where // // We adjust this BEFORE we create the drop (e.g., `drops[n]`) // because `drops[n]` should unwind to `drops[n-1]`. - debug_assert_eq!(unwind_drops.drops[unwind_to].data.local, drop_data.local); - debug_assert_eq!(unwind_drops.drops[unwind_to].data.kind, drop_data.kind); - unwind_to = unwind_drops.drops[unwind_to].next; + debug_assert_eq!(unwind_drops.drop_nodes[unwind_to].data.local, drop_data.local); + debug_assert_eq!(unwind_drops.drop_nodes[unwind_to].data.kind, drop_data.kind); + unwind_to = unwind_drops.drop_nodes[unwind_to].next; if let Some(idx) = dropline_to { - debug_assert_eq!(coroutine_drops.drops[idx].data.local, drop_data.local); - debug_assert_eq!(coroutine_drops.drops[idx].data.kind, drop_data.kind); - dropline_to = Some(coroutine_drops.drops[idx].next); + debug_assert_eq!(coroutine_drops.drop_nodes[idx].data.local, drop_data.local); + debug_assert_eq!(coroutine_drops.drop_nodes[idx].data.kind, drop_data.kind); + dropline_to = Some(coroutine_drops.drop_nodes[idx].next); } // If the operand has been moved, and we are not on an unwind @@ -1597,9 +1603,12 @@ where // cases we emit things ALSO on the unwind path, so we need to adjust // `unwind_to` in that case. if storage_dead_on_unwind { - debug_assert_eq!(unwind_drops.drops[unwind_to].data.local, drop_data.local); - debug_assert_eq!(unwind_drops.drops[unwind_to].data.kind, drop_data.kind); - unwind_to = unwind_drops.drops[unwind_to].next; + debug_assert_eq!( + unwind_drops.drop_nodes[unwind_to].data.local, + drop_data.local + ); + debug_assert_eq!(unwind_drops.drop_nodes[unwind_to].data.kind, drop_data.kind); + unwind_to = unwind_drops.drop_nodes[unwind_to].next; } // If the operand has been moved, and we are not on an unwind @@ -1628,14 +1637,17 @@ where // the storage-dead has completed, we need to adjust the `unwind_to` pointer // so that any future drops we emit will not register storage-dead. if storage_dead_on_unwind { - debug_assert_eq!(unwind_drops.drops[unwind_to].data.local, drop_data.local); - debug_assert_eq!(unwind_drops.drops[unwind_to].data.kind, drop_data.kind); - unwind_to = unwind_drops.drops[unwind_to].next; + debug_assert_eq!( + unwind_drops.drop_nodes[unwind_to].data.local, + drop_data.local + ); + debug_assert_eq!(unwind_drops.drop_nodes[unwind_to].data.kind, drop_data.kind); + unwind_to = unwind_drops.drop_nodes[unwind_to].next; } if let Some(idx) = dropline_to { - debug_assert_eq!(coroutine_drops.drops[idx].data.local, drop_data.local); - debug_assert_eq!(coroutine_drops.drops[idx].data.kind, drop_data.kind); - dropline_to = Some(coroutine_drops.drops[idx].next); + debug_assert_eq!(coroutine_drops.drop_nodes[idx].data.local, drop_data.local); + debug_assert_eq!(coroutine_drops.drop_nodes[idx].data.kind, drop_data.kind); + dropline_to = Some(coroutine_drops.drop_nodes[idx].next); } // Only temps and vars need their storage dead. assert!(local.index() > arg_count); @@ -1662,10 +1674,10 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { let is_coroutine = self.coroutine.is_some(); // Link the exit drop tree to unwind drop tree. - if drops.drops.iter().any(|drop_node| drop_node.data.kind == DropKind::Value) { + if drops.drop_nodes.iter().any(|drop_node| drop_node.data.kind == DropKind::Value) { let unwind_target = self.diverge_cleanup_target(else_scope, span); let mut unwind_indices = IndexVec::from_elem_n(unwind_target, 1); - for (drop_idx, drop_node) in drops.drops.iter_enumerated().skip(1) { + for (drop_idx, drop_node) in drops.drop_nodes.iter_enumerated().skip(1) { match drop_node.data.kind { DropKind::Storage | DropKind::ForLint => { if is_coroutine { @@ -1694,13 +1706,13 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { } // Link the exit drop tree to dropline drop tree (coroutine drop path) for async drops if is_coroutine - && drops.drops.iter().any(|DropNode { data, next: _ }| { + && drops.drop_nodes.iter().any(|DropNode { data, next: _ }| { data.kind == DropKind::Value && self.is_async_drop(data.local) }) { let dropline_target = self.diverge_dropline_target(else_scope, span); let mut dropline_indices = IndexVec::from_elem_n(dropline_target, 1); - for (drop_idx, drop_data) in drops.drops.iter_enumerated().skip(1) { + for (drop_idx, drop_data) in drops.drop_nodes.iter_enumerated().skip(1) { match drop_data.data.kind { DropKind::Storage | DropKind::ForLint => { let coroutine_drop = self @@ -1768,11 +1780,11 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { // prevent drop elaboration from creating drop flags that would have // to be captured by the coroutine. I'm not sure how important this // optimization is, but it is here. - for (drop_idx, drop_node) in drops.drops.iter_enumerated() { + for (drop_idx, drop_node) in drops.drop_nodes.iter_enumerated() { if let DropKind::Value = drop_node.data.kind && let Some(bb) = blocks[drop_idx] { - debug_assert!(drop_node.next < drops.drops.next_index()); + debug_assert!(drop_node.next < drops.drop_nodes.next_index()); drops.entry_points.push((drop_node.next, bb)); } } From 84bb48fc886d5de72c86fb56c11f8586ca465647 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 21 May 2025 05:48:40 +1000 Subject: [PATCH 44/80] Factor out some repeated code in `build_exit_tree`. --- compiler/rustc_mir_build/src/builder/scope.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index d7900cb0845e..28d72f73155a 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -1713,28 +1713,22 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { let dropline_target = self.diverge_dropline_target(else_scope, span); let mut dropline_indices = IndexVec::from_elem_n(dropline_target, 1); for (drop_idx, drop_data) in drops.drop_nodes.iter_enumerated().skip(1) { + let coroutine_drop = self + .scopes + .coroutine_drops + .add_drop(drop_data.data, dropline_indices[drop_data.next]); match drop_data.data.kind { - DropKind::Storage | DropKind::ForLint => { - let coroutine_drop = self - .scopes - .coroutine_drops - .add_drop(drop_data.data, dropline_indices[drop_data.next]); - dropline_indices.push(coroutine_drop); - } + DropKind::Storage | DropKind::ForLint => {} DropKind::Value => { - let coroutine_drop = self - .scopes - .coroutine_drops - .add_drop(drop_data.data, dropline_indices[drop_data.next]); if self.is_async_drop(drop_data.data.local) { self.scopes.coroutine_drops.add_entry_point( blocks[drop_idx].unwrap(), dropline_indices[drop_data.next], ); } - dropline_indices.push(coroutine_drop); } } + dropline_indices.push(coroutine_drop); } } blocks[ROOT_NODE].map(BasicBlock::unit) From ec8baa5d43903a6f39ebc36370120db129a52deb Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 21 May 2025 05:54:13 +1000 Subject: [PATCH 45/80] Avoid `fold`/`flat_map`. This pattern of iterating over scopes and drops occurs multiple times in this file, with slight variations. All of them use `for` loops except this one. This commits changes it for consistency. --- compiler/rustc_mir_build/src/builder/scope.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 28d72f73155a..67988f1fcbc2 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -725,11 +725,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { drops }; - let drop_idx = self.scopes.scopes[scope_index + 1..] - .iter() - .flat_map(|scope| &scope.drops) - .fold(ROOT_NODE, |drop_idx, &drop| drops.add_drop(drop, drop_idx)); - + let mut drop_idx = ROOT_NODE; + for scope in &self.scopes.scopes[scope_index + 1..] { + for drop in &scope.drops { + drop_idx = drops.add_drop(*drop, drop_idx); + } + } drops.add_entry_point(block, drop_idx); // `build_drop_trees` doesn't have access to our source_info, so we From 7baa85d16b05bcb6bc173471f5e6b8263057bed5 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 27 May 2025 06:44:34 +0300 Subject: [PATCH 46/80] Fix inference of `AsyncFnX` return type --- .../crates/hir-ty/src/chalk_db.rs | 2 +- .../crates/hir-ty/src/display.rs | 2 + .../crates/hir-ty/src/infer/closure.rs | 56 +++++++++++++++---- .../crates/hir-ty/src/tests/traits.rs | 27 +++++++++ .../rust-analyzer/crates/hir-ty/src/traits.rs | 5 ++ 5 files changed, 81 insertions(+), 11 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index cd799c03ddf7..22b96b55cbb9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -259,7 +259,7 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { } fn well_known_trait_id( &self, - well_known_trait: rust_ir::WellKnownTrait, + well_known_trait: WellKnownTrait, ) -> Option> { let lang_attr = lang_item_from_well_known_trait(well_known_trait); let trait_ = lang_attr.resolve_trait(self.db, self.krate)?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index f0989d9de91f..f210dd8799f9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -1463,6 +1463,8 @@ impl HirDisplay for Ty { } if f.closure_style == ClosureStyle::RANotation || !sig.ret().is_unit() { write!(f, " -> ")?; + // FIXME: We display `AsyncFn` as `-> impl Future`, but this is hard to fix because + // we don't have a trait environment here, required to normalize `::Output`. sig.ret().hir_fmt(f)?; } } else { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index 800897c6fc3a..bd57ca891620 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -38,7 +38,7 @@ use crate::{ infer::{BreakableKind, CoerceMany, Diverges, coerce::CoerceNever}, make_binders, mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem}, - to_chalk_trait_id, + to_assoc_type_id, to_chalk_trait_id, traits::FnTrait, utils::{self, elaborate_clause_supertraits}, }; @@ -245,7 +245,7 @@ impl InferenceContext<'_> { } fn deduce_closure_kind_from_predicate_clauses( - &self, + &mut self, expected_ty: &Ty, clauses: impl DoubleEndedIterator, closure_kind: ClosureKind, @@ -378,7 +378,7 @@ impl InferenceContext<'_> { } fn deduce_sig_from_projection( - &self, + &mut self, closure_kind: ClosureKind, projection_ty: &ProjectionTy, projected_ty: &Ty, @@ -392,13 +392,16 @@ impl InferenceContext<'_> { // For now, we only do signature deduction based off of the `Fn` and `AsyncFn` traits, // for closures and async closures, respectively. - match closure_kind { - ClosureKind::Closure | ClosureKind::Async - if self.fn_trait_kind_from_trait_id(trait_).is_some() => - { - self.extract_sig_from_projection(projection_ty, projected_ty) - } - _ => None, + let fn_trait_kind = self.fn_trait_kind_from_trait_id(trait_)?; + if !matches!(closure_kind, ClosureKind::Closure | ClosureKind::Async) { + return None; + } + if fn_trait_kind.is_async() { + // If the expected trait is `AsyncFn(...) -> X`, we don't know what the return type is, + // but we do know it must implement `Future`. + self.extract_async_fn_sig_from_projection(projection_ty, projected_ty) + } else { + self.extract_sig_from_projection(projection_ty, projected_ty) } } @@ -424,6 +427,39 @@ impl InferenceContext<'_> { ))) } + fn extract_async_fn_sig_from_projection( + &mut self, + projection_ty: &ProjectionTy, + projected_ty: &Ty, + ) -> Option> { + let arg_param_ty = projection_ty.substitution.as_slice(Interner)[1].assert_ty_ref(Interner); + + let TyKind::Tuple(_, input_tys) = arg_param_ty.kind(Interner) else { + return None; + }; + + let ret_param_future_output = projected_ty; + let ret_param_future = self.table.new_type_var(); + let future_output = + LangItem::FutureOutput.resolve_type_alias(self.db, self.resolver.krate())?; + let future_projection = crate::AliasTy::Projection(crate::ProjectionTy { + associated_ty_id: to_assoc_type_id(future_output), + substitution: Substitution::from1(Interner, ret_param_future.clone()), + }); + self.table.register_obligation( + crate::AliasEq { alias: future_projection, ty: ret_param_future_output.clone() } + .cast(Interner), + ); + + Some(FnSubst(Substitution::from_iter( + Interner, + input_tys.iter(Interner).map(|t| t.cast(Interner)).chain(Some(GenericArg::new( + Interner, + chalk_ir::GenericArgData::Ty(ret_param_future), + ))), + ))) + } + fn fn_trait_kind_from_trait_id(&self, trait_id: hir_def::TraitId) -> Option { FnTrait::from_lang_item(self.db.lang_attr(trait_id.into())?) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 2b527a4ae12e..e5d1fbe9defe 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -4903,3 +4903,30 @@ fn main() { "#]], ); } + +#[test] +fn async_fn_return_type() { + check_infer( + r#" +//- minicore: async_fn +fn foo R, R>(_: F) -> R { + loop {} +} + +fn main() { + foo(async move || ()); +} + "#, + expect![[r#" + 29..30 '_': F + 40..55 '{ loop {} }': R + 46..53 'loop {}': ! + 51..53 '{}': () + 67..97 '{ ...()); }': () + 73..76 'foo': fn foo impl Future, ()>(impl AsyncFn() -> impl Future) + 73..94 'foo(as...|| ())': () + 77..93 'async ... || ()': impl AsyncFn() -> impl Future + 91..93 '()': () + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index f9f8776cff7c..7414b4fc6070 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -291,4 +291,9 @@ impl FnTrait { pub fn get_id(self, db: &dyn HirDatabase, krate: Crate) -> Option { self.lang_item().resolve_trait(db, krate) } + + #[inline] + pub(crate) fn is_async(self) -> bool { + matches!(self, FnTrait::AsyncFn | FnTrait::AsyncFnMut | FnTrait::AsyncFnOnce) + } } From 68ff7f2878e25b99970957964696edd9a36271ed Mon Sep 17 00:00:00 2001 From: Vincent Esche Date: Mon, 26 May 2025 13:27:01 +0200 Subject: [PATCH 47/80] Make `Semantics<'db, DB>` support `Semantics<'db, dyn HirDatabase>`, by use of `DB: ?Sized` --- src/tools/rust-analyzer/crates/hir/src/semantics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 247d6406973d..117d9c492008 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -147,7 +147,7 @@ impl TypeInfo { } /// Primary API to get semantic information, like types, from syntax trees. -pub struct Semantics<'db, DB> { +pub struct Semantics<'db, DB: ?Sized> { pub db: &'db DB, imp: SemanticsImpl<'db>, } From 871327e9c7a6d44e233b31213858a224451afa74 Mon Sep 17 00:00:00 2001 From: binarycat Date: Thu, 22 May 2025 17:44:10 -0500 Subject: [PATCH 48/80] rustdoc: linking to a local proc macro no longer warns fixes https://github.com/rust-lang/rust/issues/91274 Co-authored-by: Guillaume Gomez --- .../passes/collect_intra_doc_links.rs | 36 ++++++++++++++----- .../intra-doc/bad-link-to-proc-macro.rs | 21 +++++++++++ .../intra-doc/bad-link-to-proc-macro.stderr | 22 ++++++++++++ tests/rustdoc/intra-doc/link-to-proc-macro.rs | 13 +++++++ 4 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 tests/rustdoc-ui/intra-doc/bad-link-to-proc-macro.rs create mode 100644 tests/rustdoc-ui/intra-doc/bad-link-to-proc-macro.stderr create mode 100644 tests/rustdoc/intra-doc/link-to-proc-macro.rs diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index f3e2138d1a57..b3a57ff3ff39 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -22,6 +22,7 @@ use rustc_resolve::rustdoc::{ MalformedGenerics, has_primitive_or_keyword_docs, prepare_to_doc_link_resolution, source_span_for_markdown_range, strip_generics_from_path, }; +use rustc_session::config::CrateType; use rustc_session::lint::Lint; use rustc_span::BytePos; use rustc_span::hygiene::MacroKind; @@ -1174,7 +1175,6 @@ impl LinkCollector<'_, '_> { #[allow(rustc::potential_query_instability)] pub(crate) fn resolve_ambiguities(&mut self) { let mut ambiguous_links = mem::take(&mut self.ambiguous_links); - for ((item_id, path_str), info_items) in ambiguous_links.iter_mut() { for info in info_items { info.resolved.retain(|(res, _)| match res { @@ -2232,15 +2232,35 @@ fn ambiguity_error( emit_error: bool, ) -> bool { let mut descrs = FxHashSet::default(); - let kinds = candidates + // proc macro can exist in multiple namespaces at once, so we need to compare `DefIds` + // to remove the candidate in the fn namespace. + let mut possible_proc_macro_id = None; + let is_proc_macro_crate = cx.tcx.crate_types() == &[CrateType::ProcMacro]; + let mut kinds = candidates .iter() - .map( - |(res, def_id)| { - if let Some(def_id) = def_id { Res::from_def_id(cx.tcx, *def_id) } else { *res } - }, - ) - .filter(|res| descrs.insert(res.descr())) + .map(|(res, def_id)| { + let r = + if let Some(def_id) = def_id { Res::from_def_id(cx.tcx, *def_id) } else { *res }; + if is_proc_macro_crate && let Res::Def(DefKind::Macro(_), id) = r { + possible_proc_macro_id = Some(id); + } + r + }) .collect::>(); + // In order to properly dedup proc macros, we have to do it in two passes: + // 1. Completing the full traversal to find the possible duplicate in the macro namespace, + // 2. Another full traversal to eliminate the candidate in the fn namespace. + // + // Thus, we have to do an iteration after collection is finished. + // + // As an optimization, we only deduplicate if we're in a proc-macro crate, + // and only if we already found something that looks like a proc macro. + if is_proc_macro_crate && let Some(macro_id) = possible_proc_macro_id { + kinds.retain(|res| !matches!(res, Res::Def(DefKind::Fn, fn_id) if macro_id == *fn_id)); + } + + kinds.retain(|res| descrs.insert(res.descr())); + if descrs.len() == 1 { // There is no way for users to disambiguate at this point, so better return the first // candidate and not show a warning. diff --git a/tests/rustdoc-ui/intra-doc/bad-link-to-proc-macro.rs b/tests/rustdoc-ui/intra-doc/bad-link-to-proc-macro.rs new file mode 100644 index 000000000000..b449465768ef --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/bad-link-to-proc-macro.rs @@ -0,0 +1,21 @@ +//@ compile-flags: --crate-type=proc-macro --document-private-items +#![deny(rustdoc::broken_intra_doc_links)] + +//! Link to [`m`]. +//~^ ERROR `m` is both a module and a macro + +// test a further edge case related to https://github.com/rust-lang/rust/issues/91274 + +// we need to make sure that when there is actually an ambiguity +// in a proc-macro crate, we print out a sensible error. +// because proc macro crates can't normally export modules, +// this can only happen in --document-private-items mode. + +extern crate proc_macro; + +mod m {} + +#[proc_macro] +pub fn m(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + input +} diff --git a/tests/rustdoc-ui/intra-doc/bad-link-to-proc-macro.stderr b/tests/rustdoc-ui/intra-doc/bad-link-to-proc-macro.stderr new file mode 100644 index 000000000000..09a5d26ededc --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/bad-link-to-proc-macro.stderr @@ -0,0 +1,22 @@ +error: `m` is both a module and a macro + --> $DIR/bad-link-to-proc-macro.rs:4:15 + | +LL | //! Link to [`m`]. + | ^ ambiguous link + | +note: the lint level is defined here + --> $DIR/bad-link-to-proc-macro.rs:2:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: to link to the module, prefix with `mod@` + | +LL | //! Link to [`mod@m`]. + | ++++ +help: to link to the macro, add an exclamation mark + | +LL | //! Link to [`m!`]. + | + + +error: aborting due to 1 previous error + diff --git a/tests/rustdoc/intra-doc/link-to-proc-macro.rs b/tests/rustdoc/intra-doc/link-to-proc-macro.rs new file mode 100644 index 000000000000..6c289078db86 --- /dev/null +++ b/tests/rustdoc/intra-doc/link-to-proc-macro.rs @@ -0,0 +1,13 @@ +//@ compile-flags: --crate-type=proc-macro +//@ has 'foo/index.html' '//a[@href="macro.my_macro.html"]' 'my_macro' +//! Link to [`my_macro`]. +#![crate_name = "foo"] + +// regression test for https://github.com/rust-lang/rust/issues/91274 + +extern crate proc_macro; + +#[proc_macro] +pub fn my_macro(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + input +} From a83f8d02eaf36b36a7ed495e43b8bf891b6fc1af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 2 May 2025 20:22:13 +0200 Subject: [PATCH 49/80] Always evaluate free lifetime-generic constants Co-authored-by: Michael Goulet --- compiler/rustc_hir_analysis/src/lib.rs | 4 +++- compiler/rustc_monomorphize/src/collector.rs | 2 +- tests/ui/generic-const-items/def-site-eval.fail.stderr | 4 ++-- tests/ui/generic-const-items/def-site-eval.rs | 7 +++---- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 010c6c376fe3..a64c24f5455b 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -203,7 +203,9 @@ pub fn check_crate(tcx: TyCtxt<'_>) { tcx.ensure_ok().eval_static_initializer(item_def_id); check::maybe_check_static_with_link_section(tcx, item_def_id); } - DefKind::Const if tcx.generics_of(item_def_id).is_empty() => { + DefKind::Const if !tcx.generics_of(item_def_id).own_requires_monomorphization() => { + // FIXME(generic_const_items): Passing empty instead of identity args is fishy but + // seems to be fine for now. Revisit this! let instance = ty::Instance::new_raw(item_def_id.into(), ty::GenericArgs::empty()); let cid = GlobalId { instance, promoted: None }; let typing_env = ty::TypingEnv::fully_monomorphized(); diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index b3d7eaf332b2..1ee977a5457e 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1483,7 +1483,7 @@ impl<'v> RootCollector<'_, 'v> { // But even just declaring them must collect the items they refer to // unless their generics require monomorphization. - if !self.tcx.generics_of(id.owner_id).requires_monomorphization(self.tcx) + if !self.tcx.generics_of(id.owner_id).own_requires_monomorphization() && let Ok(val) = self.tcx.const_eval_poly(id.owner_id.to_def_id()) { collect_const_value(self.tcx, val, self.output); diff --git a/tests/ui/generic-const-items/def-site-eval.fail.stderr b/tests/ui/generic-const-items/def-site-eval.fail.stderr index fa07f3855224..4e7d9d8154a0 100644 --- a/tests/ui/generic-const-items/def-site-eval.fail.stderr +++ b/tests/ui/generic-const-items/def-site-eval.fail.stderr @@ -1,5 +1,5 @@ -error[E0080]: evaluation of `_::<'_>` failed - --> $DIR/def-site-eval.rs:14:20 +error[E0080]: evaluation of constant value failed + --> $DIR/def-site-eval.rs:13:20 | LL | const _<'_a>: () = panic!(); | ^^^^^^^^ evaluation panicked: explicit panic diff --git a/tests/ui/generic-const-items/def-site-eval.rs b/tests/ui/generic-const-items/def-site-eval.rs index 3ed7f96aed02..b95e40c05d4d 100644 --- a/tests/ui/generic-const-items/def-site-eval.rs +++ b/tests/ui/generic-const-items/def-site-eval.rs @@ -1,16 +1,15 @@ //! Test that we only evaluate free const items (their def site to be clear) //! whose generics don't require monomorphization. #![feature(generic_const_items)] -#![allow(incomplete_features)] +#![expect(incomplete_features)] //@ revisions: fail pass -//@[fail] build-fail (we require monomorphization) -//@[pass] build-pass (we require monomorphization) +//@[pass] check-pass const _<_T>: () = panic!(); const _: () = panic!(); #[cfg(fail)] -const _<'_a>: () = panic!(); //[fail]~ ERROR evaluation of `_::<'_>` failed +const _<'_a>: () = panic!(); //[fail]~ ERROR evaluation of constant value failed fn main() {} From db21caf5ba1161d157e62956039f0ff2493454a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 2 May 2025 20:22:35 +0200 Subject: [PATCH 50/80] Drive-by: Delete dead TyCtxtEnsureOk::const_eval_poly --- .../rustc_middle/src/mir/interpret/queries.rs | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 4a5c42c721c1..97db45a70d7f 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -9,7 +9,6 @@ use super::{ ReportedErrorInfo, }; use crate::mir; -use crate::query::TyCtxtEnsureOk; use crate::ty::{self, GenericArgs, TyCtxt, TypeVisitableExt}; impl<'tcx> TyCtxt<'tcx> { @@ -197,24 +196,3 @@ impl<'tcx> TyCtxt<'tcx> { } } } - -impl<'tcx> TyCtxtEnsureOk<'tcx> { - /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts - /// that can't take any generic arguments like const items or enum discriminants. If a - /// generic parameter is used within the constant `ErrorHandled::TooGeneric` will be returned. - #[instrument(skip(self), level = "debug")] - pub fn const_eval_poly(self, def_id: DefId) { - // In some situations def_id will have generic parameters within scope, but they aren't allowed - // to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters - // into `const_eval` which will return `ErrorHandled::TooGeneric` if any of them are - // encountered. - let args = GenericArgs::identity_for_item(self.tcx, def_id); - let instance = ty::Instance::new_raw(def_id, self.tcx.erase_regions(args)); - let cid = GlobalId { instance, promoted: None }; - let typing_env = ty::TypingEnv::post_analysis(self.tcx, def_id); - // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should - // improve caching of queries. - let inputs = self.tcx.erase_regions(typing_env.as_query_input(cid)); - self.eval_to_const_value_raw(inputs) - } -} From e9080948c64cdb12014f11004a921a676fbc0964 Mon Sep 17 00:00:00 2001 From: bohan Date: Sun, 25 May 2025 23:14:59 +0800 Subject: [PATCH 51/80] consider glob imports in cfg suggestion --- compiler/rustc_expand/src/expand.rs | 6 +- compiler/rustc_resolve/src/diagnostics.rs | 50 +++++++++++- tests/ui/cfg/diagnostics-reexport-2.rs | 61 +++++++++++++++ tests/ui/cfg/diagnostics-reexport-2.stderr | 88 ++++++++++++++++++++++ 4 files changed, 200 insertions(+), 5 deletions(-) create mode 100644 tests/ui/cfg/diagnostics-reexport-2.rs create mode 100644 tests/ui/cfg/diagnostics-reexport-2.stderr diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 81d4d59ee045..e5749ba96a6d 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1319,10 +1319,10 @@ impl InvocationCollectorNode for P { let mut idents = Vec::new(); collect_use_tree_leaves(ut, &mut idents); - return idents; + idents + } else { + self.kind.ident().into_iter().collect() } - - if let Some(ident) = self.kind.ident() { vec![ident] } else { vec![] } } } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index d09750fa281b..201b1c0a493b 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -6,7 +6,7 @@ use rustc_ast::{ }; use rustc_ast_pretty::pprust; use rustc_attr_data_structures::{self as attr, Stability}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::{ @@ -2623,7 +2623,53 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; for &StrippedCfgItem { parent_module, ident, ref cfg } in symbols { - if parent_module != module || ident.name != *segment { + if ident.name != *segment { + continue; + } + + fn comes_from_same_module_for_glob( + r: &Resolver<'_, '_>, + parent_module: DefId, + module: DefId, + visited: &mut FxHashMap, + ) -> bool { + if let Some(&cached) = visited.get(&parent_module) { + // this branch is prevent from being called recursively infinity, + // because there has some cycles in globs imports, + // see more spec case at `tests/ui/cfg/diagnostics-reexport-2.rs#reexport32` + return cached; + } + visited.insert(parent_module, false); + let res = r.module_map.get(&parent_module).is_some_and(|m| { + for importer in m.glob_importers.borrow().iter() { + if let Some(next_parent_module) = importer.parent_scope.module.opt_def_id() + { + if next_parent_module == module + || comes_from_same_module_for_glob( + r, + next_parent_module, + module, + visited, + ) + { + return true; + } + } + } + false + }); + visited.insert(parent_module, res); + res + } + + let comes_from_same_module = parent_module == module + || comes_from_same_module_for_glob( + self, + parent_module, + module, + &mut Default::default(), + ); + if !comes_from_same_module { continue; } diff --git a/tests/ui/cfg/diagnostics-reexport-2.rs b/tests/ui/cfg/diagnostics-reexport-2.rs new file mode 100644 index 000000000000..f66b9ed99ee6 --- /dev/null +++ b/tests/ui/cfg/diagnostics-reexport-2.rs @@ -0,0 +1,61 @@ +// issue#141256 + +mod original { + #[cfg(false)] + //~^ NOTE the item is gated here + //~| NOTE the item is gated here + //~| NOTE the item is gated here + //~| NOTE the item is gated here + //~| NOTE the item is gated here + pub mod gated { + //~^ NOTE found an item that was configured out + //~| NOTE found an item that was configured out + //~| NOTE found an item that was configured out + //~| NOTE found an item that was configured out + //~| NOTE found an item that was configured out + pub fn foo() {} + } +} + +mod reexport { + pub use super::original::*; +} + +mod reexport2 { + pub use super::reexport::*; +} + +mod reexport30 { + pub use super::original::*; + pub use super::reexport31::*; +} + +mod reexport31 { + pub use super::reexport30::*; +} + +mod reexport32 { + pub use super::reexport30::*; +} + +fn main() { + reexport::gated::foo(); + //~^ ERROR failed to resolve: could not find `gated` in `reexport` + //~| NOTE could not find `gated` in `reexport` + + reexport2::gated::foo(); + //~^ ERROR failed to resolve: could not find `gated` in `reexport2` + //~| NOTE could not find `gated` in `reexport2` + + reexport30::gated::foo(); + //~^ ERROR failed to resolve: could not find `gated` in `reexport30` + //~| NOTE could not find `gated` in `reexport30` + + reexport31::gated::foo(); + //~^ ERROR failed to resolve: could not find `gated` in `reexport31` + //~| NOTE could not find `gated` in `reexport31` + + reexport32::gated::foo(); + //~^ ERROR failed to resolve: could not find `gated` in `reexport32` + //~| NOTE could not find `gated` in `reexport32` +} diff --git a/tests/ui/cfg/diagnostics-reexport-2.stderr b/tests/ui/cfg/diagnostics-reexport-2.stderr new file mode 100644 index 000000000000..95ac5a19b0b9 --- /dev/null +++ b/tests/ui/cfg/diagnostics-reexport-2.stderr @@ -0,0 +1,88 @@ +error[E0433]: failed to resolve: could not find `gated` in `reexport` + --> $DIR/diagnostics-reexport-2.rs:42:15 + | +LL | reexport::gated::foo(); + | ^^^^^ could not find `gated` in `reexport` + | +note: found an item that was configured out + --> $DIR/diagnostics-reexport-2.rs:10:13 + | +LL | pub mod gated { + | ^^^^^ +note: the item is gated here + --> $DIR/diagnostics-reexport-2.rs:4:5 + | +LL | #[cfg(false)] + | ^^^^^^^^^^^^^ + +error[E0433]: failed to resolve: could not find `gated` in `reexport2` + --> $DIR/diagnostics-reexport-2.rs:46:16 + | +LL | reexport2::gated::foo(); + | ^^^^^ could not find `gated` in `reexport2` + | +note: found an item that was configured out + --> $DIR/diagnostics-reexport-2.rs:10:13 + | +LL | pub mod gated { + | ^^^^^ +note: the item is gated here + --> $DIR/diagnostics-reexport-2.rs:4:5 + | +LL | #[cfg(false)] + | ^^^^^^^^^^^^^ + +error[E0433]: failed to resolve: could not find `gated` in `reexport30` + --> $DIR/diagnostics-reexport-2.rs:50:17 + | +LL | reexport30::gated::foo(); + | ^^^^^ could not find `gated` in `reexport30` + | +note: found an item that was configured out + --> $DIR/diagnostics-reexport-2.rs:10:13 + | +LL | pub mod gated { + | ^^^^^ +note: the item is gated here + --> $DIR/diagnostics-reexport-2.rs:4:5 + | +LL | #[cfg(false)] + | ^^^^^^^^^^^^^ + +error[E0433]: failed to resolve: could not find `gated` in `reexport31` + --> $DIR/diagnostics-reexport-2.rs:54:17 + | +LL | reexport31::gated::foo(); + | ^^^^^ could not find `gated` in `reexport31` + | +note: found an item that was configured out + --> $DIR/diagnostics-reexport-2.rs:10:13 + | +LL | pub mod gated { + | ^^^^^ +note: the item is gated here + --> $DIR/diagnostics-reexport-2.rs:4:5 + | +LL | #[cfg(false)] + | ^^^^^^^^^^^^^ + +error[E0433]: failed to resolve: could not find `gated` in `reexport32` + --> $DIR/diagnostics-reexport-2.rs:58:17 + | +LL | reexport32::gated::foo(); + | ^^^^^ could not find `gated` in `reexport32` + | +note: found an item that was configured out + --> $DIR/diagnostics-reexport-2.rs:10:13 + | +LL | pub mod gated { + | ^^^^^ +note: the item is gated here + --> $DIR/diagnostics-reexport-2.rs:4:5 + | +LL | #[cfg(false)] + | ^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0433`. From d562c46be0bb599ae52db2f3bd0b5c4d7645bd70 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 27 May 2025 10:05:50 -0700 Subject: [PATCH 52/80] CI: Add cargo tests to aarch64-apple-darwin This adds running of cargo's tests to the aarch64-apple-darwin job. The reason for this is that tier-1 targets are ostensibly supposed to run tests for host tools, but we are not doing that here. We do have fairly good coverage in Cargo's CI, but we don't have much coverage of beta or stable. I think it would be good to have a fallback here. --- src/ci/github-actions/jobs.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 1d175bd97e6a..fbb3729f21da 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -459,7 +459,9 @@ auto: - name: aarch64-apple env: - SCRIPT: ./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin + SCRIPT: > + ./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin && + ./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin src/tools/cargo RUST_CONFIGURE_ARGS: >- --enable-sanitizers --enable-profiler From a55a3705f63e0a6286a21a14c4575c04b65e6853 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Wed, 28 May 2025 08:11:14 +0900 Subject: [PATCH 53/80] fix: Skip pattern analysis on type mismatches --- .../crates/hir-ty/src/diagnostics/expr.rs | 3 +++ .../ide-diagnostics/src/handlers/type_mismatch.rs | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index 8665e9d33fcb..9eb7ffe1c719 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -324,6 +324,9 @@ impl ExprValidator { let &Statement::Let { pat, initializer, else_branch: None, .. } = stmt else { continue; }; + if self.infer.type_mismatch_for_pat(pat).is_some() { + continue; + } let Some(initializer) = initializer else { continue }; let ty = &self.infer[initializer]; if ty.contains_unknown() { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs index 5253734867e8..076df1ab0f82 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -1243,4 +1243,18 @@ fn foo(v: &Enum) { "#, ); } + + #[test] + fn regression_19844() { + check_diagnostics( + r#" +fn main() { + struct S {} + enum E { V() } + let E::V() = &S {}; + // ^^^^^^ error: expected S, found E +} +"#, + ); + } } From 56b669cd7adcc413bb1e64c3d2d7c347a82ae35a Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Wed, 21 May 2025 18:47:09 -0700 Subject: [PATCH 54/80] Disable libunwind cross-architecture unwinding Building with _LIBUNWIND_IS_NATIVE_ONLY disables code for cross-architecture unwinding it is disabled by default in LLVM [1], replicate the cmake behavior in bootstrap process It also enables some additional code that handles PAC-specific unwind info it helps compiling with the -mbranch-protection=pac or -mbranch-protection=standard flags This fixes build with clang/musl on aarch64 [1] https://github.com/llvm/llvm-project/commit/85624c5de3e831ffa01fdc2d159e3d69c30de08d Signed-off-by: Khem Raj --- src/bootstrap/src/core/build_steps/llvm.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index a37881974716..5e4a1c7d9f07 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -1430,6 +1430,7 @@ impl Step for Libunwind { cfg.flag("-funwind-tables"); cfg.flag("-fvisibility=hidden"); cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None); + cfg.define("_LIBUNWIND_IS_NATIVE_ONLY", "1"); cfg.include(root.join("include")); cfg.cargo_metadata(false); cfg.out_dir(&out_dir); @@ -1447,12 +1448,10 @@ impl Step for Libunwind { cfg.define("__NO_STRING_INLINES", None); cfg.define("__NO_MATH_INLINES", None); cfg.define("_LIBUNWIND_IS_BAREMETAL", None); - cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None); cfg.define("NDEBUG", None); } if self.target.is_windows() { cfg.define("_LIBUNWIND_HIDE_SYMBOLS", "1"); - cfg.define("_LIBUNWIND_IS_NATIVE_ONLY", "1"); } } From adcd0bf5c36ee49acf390f0d75125da4efda35ac Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 28 May 2025 09:34:08 +0800 Subject: [PATCH 55/80] Fix ICE in tokenstream with contracts from parser recovery --- compiler/rustc_parse/src/parser/stmt.rs | 13 ++++--- tests/crashes/140683.rs | 5 --- ...-tokenstream-for-contracts-issue-140683.rs | 13 +++++++ ...enstream-for-contracts-issue-140683.stderr | 34 +++++++++++++++++++ .../ui/macros/no-close-delim-issue-139248.rs | 5 ++- .../macros/no-close-delim-issue-139248.stderr | 16 +++------ 6 files changed, 60 insertions(+), 26 deletions(-) delete mode 100644 tests/crashes/140683.rs create mode 100644 tests/ui/macros/ice-in-tokenstream-for-contracts-issue-140683.rs create mode 100644 tests/ui/macros/ice-in-tokenstream-for-contracts-issue-140683.stderr diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 396ded96bde1..ccc3410674b4 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -515,8 +515,8 @@ impl<'a> Parser<'a> { fn error_block_no_opening_brace_msg(&mut self, msg: Cow<'static, str>) -> Diag<'a> { let prev = self.prev_token.span; let sp = self.token.span; - let mut e = self.dcx().struct_span_err(sp, msg); - self.label_expected_raw_ref(&mut e); + let mut err = self.dcx().struct_span_err(sp, msg); + self.label_expected_raw_ref(&mut err); let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon @@ -558,20 +558,19 @@ impl<'a> Parser<'a> { stmt.span }; self.suggest_fixes_misparsed_for_loop_head( - &mut e, + &mut err, prev.between(sp), stmt_span, &stmt.kind, ); } Err(e) => { - self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); - e.cancel(); + e.delay_as_bug(); } _ => {} } - e.span_label(sp, "expected `{`"); - e + err.span_label(sp, "expected `{`"); + err } fn suggest_fixes_misparsed_for_loop_head( diff --git a/tests/crashes/140683.rs b/tests/crashes/140683.rs deleted file mode 100644 index 74ea5c2533bb..000000000000 --- a/tests/crashes/140683.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ known-bug: #140683 -impl T { -#[core::contracts::ensures] - fn b() { (loop) } -} diff --git a/tests/ui/macros/ice-in-tokenstream-for-contracts-issue-140683.rs b/tests/ui/macros/ice-in-tokenstream-for-contracts-issue-140683.rs new file mode 100644 index 000000000000..68346a00ae1a --- /dev/null +++ b/tests/ui/macros/ice-in-tokenstream-for-contracts-issue-140683.rs @@ -0,0 +1,13 @@ +#![feature(contracts)] +#![allow(incomplete_features)] + +struct T; + +impl T { + #[core::contracts::ensures] //~ ERROR expected a `Fn(&_)` closure, found `()` + fn b() {(loop)} + //~^ ERROR expected `{`, found `)` + //~| ERROR expected `{`, found `)` +} + +fn main() {} diff --git a/tests/ui/macros/ice-in-tokenstream-for-contracts-issue-140683.stderr b/tests/ui/macros/ice-in-tokenstream-for-contracts-issue-140683.stderr new file mode 100644 index 000000000000..f1ffda2a9bee --- /dev/null +++ b/tests/ui/macros/ice-in-tokenstream-for-contracts-issue-140683.stderr @@ -0,0 +1,34 @@ +error: expected `{`, found `)` + --> $DIR/ice-in-tokenstream-for-contracts-issue-140683.rs:8:18 + | +LL | fn b() {(loop)} + | ----^ expected `{` + | | + | while parsing this `loop` expression + +error: expected `{`, found `)` + --> $DIR/ice-in-tokenstream-for-contracts-issue-140683.rs:8:18 + | +LL | fn b() {(loop)} + | ----^ expected `{` + | | + | while parsing this `loop` expression + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: expected a `Fn(&_)` closure, found `()` + --> $DIR/ice-in-tokenstream-for-contracts-issue-140683.rs:7:5 + | +LL | #[core::contracts::ensures] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | expected an `Fn(&_)` closure, found `()` + | required by a bound introduced by this call + | + = help: the trait `for<'a> Fn(&'a _)` is not implemented for `()` +note: required by a bound in `build_check_ensures` + --> $SRC_DIR/core/src/contracts.rs:LL:COL + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/macros/no-close-delim-issue-139248.rs b/tests/ui/macros/no-close-delim-issue-139248.rs index 86583b2724ed..f15234eaff1a 100644 --- a/tests/ui/macros/no-close-delim-issue-139248.rs +++ b/tests/ui/macros/no-close-delim-issue-139248.rs @@ -2,9 +2,8 @@ macro_rules! m { (static a : () = $e:expr) => { - static a : () = $e; - //~^ ERROR macro expansion ends with an incomplete expression: expected expression - } + static a: () = $e; + }; } m! { static a : () = (if b) } diff --git a/tests/ui/macros/no-close-delim-issue-139248.stderr b/tests/ui/macros/no-close-delim-issue-139248.stderr index 6ed41ae9b46a..8aa39851b4b0 100644 --- a/tests/ui/macros/no-close-delim-issue-139248.stderr +++ b/tests/ui/macros/no-close-delim-issue-139248.stderr @@ -1,33 +1,27 @@ error: expected `{`, found `)` - --> $DIR/no-close-delim-issue-139248.rs:10:27 + --> $DIR/no-close-delim-issue-139248.rs:9:27 | LL | m! { static a : () = (if b) } | ^ expected `{` | note: the `if` expression is missing a block after this condition - --> $DIR/no-close-delim-issue-139248.rs:10:26 + --> $DIR/no-close-delim-issue-139248.rs:9:26 | LL | m! { static a : () = (if b) } | ^ error: expected `{`, found `)` - --> $DIR/no-close-delim-issue-139248.rs:10:27 + --> $DIR/no-close-delim-issue-139248.rs:9:27 | LL | m! { static a : () = (if b) } | ^ expected `{` | note: the `if` expression is missing a block after this condition - --> $DIR/no-close-delim-issue-139248.rs:10:26 + --> $DIR/no-close-delim-issue-139248.rs:9:26 | LL | m! { static a : () = (if b) } | ^ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: macro expansion ends with an incomplete expression: expected expression - --> $DIR/no-close-delim-issue-139248.rs:5:28 - | -LL | static a : () = $e; - | ^ expected expression - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors From 9f94b13d7a548ccf123c5b84130a8a86cb995d5b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 28 May 2025 03:52:08 +0000 Subject: [PATCH 56/80] chore: Remove support for `concat_idents!` `concat_idents!` was deprecated in [1] and will be removed in the near future. rust-analyzer's support is independent of rustc's, so drop RA support now to make syncing easier. [1]: https://github.com/rust-lang/rust/pull/137653 --- .../macro_expansion_tests/builtin_fn_macro.rs | 18 ------------- .../crates/hir-expand/src/builtin/fn_macro.rs | 25 ------------------- .../crates/intern/src/symbol/symbols.rs | 1 - 3 files changed, 44 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index 3027aff3163a..293868df613a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -509,24 +509,6 @@ fn main() { "s"; } ); } -#[test] -fn test_concat_idents_expand() { - check( - r##" -#[rustc_builtin_macro] -macro_rules! concat_idents {} - -fn main() { concat_idents!(foo, bar); } -"##, - expect![[r##" -#[rustc_builtin_macro] -macro_rules! concat_idents {} - -fn main() { foobar; } -"##]], - ); -} - #[test] fn test_quote_string() { check( diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs index 539c72772843..3180b8dae10e 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs @@ -140,7 +140,6 @@ register_builtin! { EagerExpander: (compile_error, CompileError) => compile_error_expand, (concat, Concat) => concat_expand, - (concat_idents, ConcatIdents) => concat_idents_expand, (concat_bytes, ConcatBytes) => concat_bytes_expand, (include, Include) => include_expand, (include_bytes, IncludeBytes) => include_bytes_expand, @@ -660,30 +659,6 @@ fn concat_bytes_expand_subtree( Ok(()) } -fn concat_idents_expand( - _db: &dyn ExpandDatabase, - _arg_id: MacroCallId, - tt: &tt::TopSubtree, - span: Span, -) -> ExpandResult { - let mut err = None; - let mut ident = String::new(); - for (i, t) in tt.iter().enumerate() { - match t { - TtElement::Leaf(tt::Leaf::Ident(id)) => { - ident.push_str(id.sym.as_str()); - } - TtElement::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (), - _ => { - err.get_or_insert(ExpandError::other(span, "unexpected token")); - } - } - } - // FIXME merge spans - let ident = tt::Ident { sym: Symbol::intern(&ident), span, is_raw: tt::IdentIsRaw::No }; - ExpandResult { value: quote!(span =>#ident), err } -} - fn relative_file( db: &dyn ExpandDatabase, call_id: MacroCallId, diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index abde48d15127..fc922dd849fb 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -164,7 +164,6 @@ define_symbols! { completion, compile_error, concat_bytes, - concat_idents, concat, const_format_args, const_panic_fmt, From cfe488c7a0bf154dd060404b35d55a482c307817 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 28 May 2025 06:56:48 +0200 Subject: [PATCH 57/80] fix: Fix IDE layer not resolving some macro calls --- .../crates/hir-def/src/nameres/assoc.rs | 4 +- .../rust-analyzer/crates/hir/src/semantics.rs | 32 +++------------ .../hir/src/semantics/child_by_source.rs | 19 ++++++--- .../crates/ide/src/expand_macro.rs | 40 +++++++++++++++++++ .../rust-analyzer/src/cli/analysis_stats.rs | 2 +- 5 files changed, 62 insertions(+), 35 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs index d45709b8b903..86225d33b4e1 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs @@ -75,7 +75,7 @@ impl TraitItems { }) } - pub fn attribute_calls(&self) -> impl Iterator, MacroCallId)> + '_ { + pub fn macro_calls(&self) -> impl Iterator, MacroCallId)> + '_ { self.macro_calls.iter().flat_map(|it| it.iter()).copied() } } @@ -109,7 +109,7 @@ impl ImplItems { (Arc::new(ImplItems { items, macro_calls }), DefDiagnostics::new(diagnostics)) } - pub fn attribute_calls(&self) -> impl Iterator, MacroCallId)> + '_ { + pub fn macro_calls(&self) -> impl Iterator, MacroCallId)> + '_ { self.macro_calls.iter().flat_map(|it| it.iter()).copied() } } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 117d9c492008..5823f6260bfc 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -408,11 +408,7 @@ impl<'db> SemanticsImpl<'db> { } pub fn expand_macro_call(&self, macro_call: &ast::MacroCall) -> Option> { - let sa = self.analyze_no_infer(macro_call.syntax())?; - - let macro_call = InFile::new(sa.file_id, macro_call); - let file_id = sa.expansion(self.db, macro_call)?; - + let file_id = self.to_def(macro_call)?; let node = self.parse_or_expand(file_id.into()); Some(InFile::new(file_id.into(), node)) } @@ -434,10 +430,7 @@ impl<'db> SemanticsImpl<'db> { &self, macro_call: &ast::MacroCall, ) -> Option> { - let sa = self.analyze_no_infer(macro_call.syntax())?; - - let macro_call = InFile::new(sa.file_id, macro_call); - let file_id = sa.expansion(self.db, macro_call)?; + let file_id = self.to_def(macro_call)?; let macro_call = self.db.lookup_intern_macro_call(file_id); let skip = matches!( @@ -1097,16 +1090,7 @@ impl<'db> SemanticsImpl<'db> { let file_id = match m_cache.get(&mcall) { Some(&it) => it, None => { - let it = token - .parent() - .and_then(|parent| { - self.analyze_impl( - InFile::new(expansion, &parent), - None, - false, - ) - })? - .expansion(self.db, mcall.as_ref())?; + let it = ast::MacroCall::to_def(self, mcall.as_ref())?; m_cache.insert(mcall, it); it } @@ -1562,14 +1546,8 @@ impl<'db> SemanticsImpl<'db> { } pub fn resolve_macro_call_arm(&self, macro_call: &ast::MacroCall) -> Option { - let sa = self.analyze(macro_call.syntax())?; - self.db - .parse_macro_expansion( - sa.expansion(self.db, self.wrap_node_infile(macro_call.clone()).as_ref())?, - ) - .value - .1 - .matched_arm + let file_id = self.to_def(macro_call)?; + self.db.parse_macro_expansion(file_id).value.1.matched_arm } pub fn get_unsafe_ops(&self, def: DefWithBody) -> FxHashSet { diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs index 9393d08ad3f9..6accf9b2e9c2 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs @@ -36,9 +36,14 @@ impl ChildBySource for TraitId { fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { let data = db.trait_items(*self); - data.attribute_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each( + data.macro_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each( |(ast_id, call_id)| { - res[keys::ATTR_MACRO_CALL].insert(ast_id.to_ptr(db), call_id); + let ptr = ast_id.to_ptr(db); + if let Some(ptr) = ptr.cast::() { + res[keys::MACRO_CALL].insert(ptr, call_id); + } else { + res[keys::ATTR_MACRO_CALL].insert(ptr, call_id); + } }, ); data.items.iter().for_each(|&(_, item)| { @@ -50,10 +55,14 @@ impl ChildBySource for TraitId { impl ChildBySource for ImplId { fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { let data = db.impl_items(*self); - // FIXME: Macro calls - data.attribute_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each( + data.macro_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each( |(ast_id, call_id)| { - res[keys::ATTR_MACRO_CALL].insert(ast_id.to_ptr(db), call_id); + let ptr = ast_id.to_ptr(db); + if let Some(ptr) = ptr.cast::() { + res[keys::MACRO_CALL].insert(ptr, call_id); + } else { + res[keys::ATTR_MACRO_CALL].insert(ptr, call_id); + } }, ); data.items.iter().for_each(|&(_, item)| { diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs index 9beed2cac134..f8f9378b9e91 100644 --- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs +++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs @@ -719,4 +719,44 @@ __log!(written:%; "Test"$0); "#]], ); } + + #[test] + fn assoc_call() { + check( + r#" +macro_rules! mac { + () => { fn assoc() {} } +} +impl () { + mac$0!(); +} + "#, + expect![[r#" + mac! + fn assoc(){}"#]], + ); + } + + #[test] + fn eager() { + check( + r#" +//- minicore: concat +macro_rules! my_concat { + ($head:expr, $($tail:tt)*) => { concat!($head, $($tail)*) }; +} + + +fn test() { + _ = my_concat!( + conc$0at!("<", ">"), + "hi", + ); +} + "#, + expect![[r#" + my_concat! + "<>hi""#]], + ); + } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index 671e838421f2..12b393b80c0d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -1023,7 +1023,7 @@ impl flags::AnalysisStats { percentage(num_pats_partially_unknown, num_pats), num_pat_type_mismatches ); - eprintln!(" panics: {}", panics); + eprintln!(" panics: {panics}"); eprintln!("{:<20} {}", "Inference:", inference_time); report_metric("unknown type", num_exprs_unknown, "#"); report_metric("type mismatches", num_expr_type_mismatches, "#"); From 711546a329170d741a1f422063d7082e8d8a75e5 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 28 May 2025 07:05:48 +0200 Subject: [PATCH 58/80] Drop unnecessay code --- .../rust-analyzer/crates/hir/src/semantics.rs | 7 +---- .../crates/hir/src/source_analyzer.rs | 31 ++----------------- 2 files changed, 3 insertions(+), 35 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 5823f6260bfc..0dac64d6f2c9 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -567,9 +567,7 @@ impl<'db> SemanticsImpl<'db> { speculative_args: &ast::TokenTree, token_to_map: SyntaxToken, ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> { - let analyzer = self.analyze_no_infer(actual_macro_call.syntax())?; - let macro_call = InFile::new(analyzer.file_id, actual_macro_call); - let macro_file = analyzer.expansion(self.db, macro_call)?; + let macro_file = self.to_def(actual_macro_call)?; hir_expand::db::expand_speculative( self.db, macro_file, @@ -1535,9 +1533,6 @@ impl<'db> SemanticsImpl<'db> { .and_then(|call| macro_call_to_macro_id(ctx, call)) .map(Into::into) }) - .or_else(|| { - self.analyze(macro_call.value.syntax())?.resolve_macro_call(self.db, macro_call) - }) } pub fn is_proc_macro_call(&self, macro_call: InFile<&ast::MacroCall>) -> bool { diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index be581292152d..d22812d3c692 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -26,12 +26,12 @@ use hir_def::{ }, hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat}, lang_item::LangItem, - nameres::{MacroSubNs, block_def_map, crate_def_map}, + nameres::MacroSubNs, resolver::{HasResolver, Resolver, TypeNs, ValueNs, resolver_for_scope}, type_ref::{Mutability, TypeRefId}, }; use hir_expand::{ - HirFileId, InFile, MacroCallId, + HirFileId, InFile, mod_path::{ModPath, PathKind, path}, name::{AsName, Name}, }; @@ -218,18 +218,6 @@ impl<'db> SourceAnalyzer<'db> { }) } - pub(crate) fn expansion( - &self, - db: &dyn HirDatabase, - macro_call: InFile<&ast::MacroCall>, - ) -> Option { - self.store_sm().and_then(|sm| sm.expansion(macro_call)).or_else(|| { - let ast_id_map = db.ast_id_map(macro_call.file_id); - let call_ast_id = macro_call.with_value(ast_id_map.ast_id(macro_call.value)); - self.resolver.item_scopes().find_map(|scope| scope.macro_invoc(call_ast_id)) - }) - } - fn trait_environment(&self, db: &'db dyn HirDatabase) -> Arc { self.body_().map(|(def, ..)| def).map_or_else( || TraitEnvironment::empty(self.resolver.krate()), @@ -753,21 +741,6 @@ impl<'db> SourceAnalyzer<'db> { )) } - pub(crate) fn resolve_macro_call( - &self, - db: &dyn HirDatabase, - macro_call: InFile<&ast::MacroCall>, - ) -> Option { - self.expansion(db, macro_call).and_then(|it| { - let def = it.lookup(db).def; - let def_map = match def.block { - Some(block) => block_def_map(db, base_db::salsa::plumbing::FromId::from_id(block)), - None => crate_def_map(db, def.krate), - }; - def_map.macro_def_to_macro_id.get(&def.kind.erased_ast_id()).map(|it| (*it).into()) - }) - } - pub(crate) fn resolve_bind_pat_to_const( &self, db: &'db dyn HirDatabase, From 7ec351ec7caa66ed4ef141f670dd4795692fd1c1 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 28 May 2025 07:06:03 +0200 Subject: [PATCH 59/80] Back out "Fix IDE resolution of item macros" This backs out commit 3e0ab7219a5464999652beca22698cd46e1e48e8. --- src/tools/rust-analyzer/crates/hir-def/src/db.rs | 3 --- src/tools/rust-analyzer/crates/hir-def/src/resolver.rs | 9 --------- src/tools/rust-analyzer/crates/hir-expand/src/lib.rs | 2 -- 3 files changed, 14 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index 6f9340a0e4d0..4a9a3b12cfab 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -422,7 +422,6 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { let makro = &item_tree[loc.id.value]; MacroDefId { krate: loc.container.krate, - block: loc.container.block.map(|block| salsa::plumbing::AsId::as_id(&block)), kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()), local_inner: false, allow_internal_unsafe: loc.allow_internal_unsafe, @@ -436,7 +435,6 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { let makro = &item_tree[loc.id.value]; MacroDefId { krate: loc.container.krate, - block: loc.container.block.map(|block| salsa::plumbing::AsId::as_id(&block)), kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()), local_inner: loc.flags.contains(MacroRulesLocFlags::LOCAL_INNER), allow_internal_unsafe: loc @@ -452,7 +450,6 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { let makro = &item_tree[loc.id.value]; MacroDefId { krate: loc.container.krate, - block: None, kind: MacroDefKind::ProcMacro( InFile::new(loc.id.file_id(), makro.ast_id), loc.expander, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 416bcbb096bd..16988ddf04b2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -696,15 +696,6 @@ impl<'db> Resolver<'db> { &def_map[local_id].scope } - pub fn item_scopes(&self) -> impl Iterator { - self.scopes() - .filter_map(move |scope| match scope { - Scope::BlockScope(m) => Some(&m.def_map[m.module_id].scope), - _ => None, - }) - .chain(std::iter::once(&self.module_scope.def_map[self.module_scope.module_id].scope)) - } - pub fn krate(&self) -> Crate { self.module_scope.def_map.krate() } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index 19cd0298e93d..d844d8f41eef 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -258,8 +258,6 @@ pub struct MacroCallLoc { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct MacroDefId { pub krate: Crate, - // FIXME: In `hir-expand` we can't refer to `BlockId`. - pub block: Option, pub edition: Edition, pub kind: MacroDefKind, pub local_inner: bool, From 636495cdec1352075b03c46198a7d6d75893192d Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Wed, 28 May 2025 11:15:33 +0900 Subject: [PATCH 60/80] feat: Render padding information when hovering on structs --- src/tools/rust-analyzer/crates/hir/src/lib.rs | 53 ++++++++ .../rust-analyzer/crates/ide/src/hover.rs | 1 + .../crates/ide/src/hover/render.rs | 76 +++++++++-- .../crates/ide/src/hover/tests.rs | 128 ++++++++++++++++-- .../crates/rust-analyzer/src/config.rs | 3 + .../docs/book/src/configuration_generated.md | 7 + .../rust-analyzer/editors/code/package.json | 27 ++++ 7 files changed, 272 insertions(+), 23 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 3a91050d15fa..e8218cf8611f 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -5972,6 +5972,59 @@ impl Layout { } } + pub fn tail_padding(&self, field_size: &mut impl FnMut(usize) -> Option) -> Option { + match self.0.fields { + layout::FieldsShape::Primitive => None, + layout::FieldsShape::Union(_) => None, + layout::FieldsShape::Array { stride, count } => count.checked_sub(1).and_then(|tail| { + let tail_field_size = field_size(tail as usize)?; + let offset = stride.bytes() * tail; + self.0.size.bytes().checked_sub(offset)?.checked_sub(tail_field_size) + }), + layout::FieldsShape::Arbitrary { ref offsets, ref memory_index } => { + let tail = memory_index.last_index()?; + let tail_field_size = field_size(tail.0.into_raw().into_u32() as usize)?; + let offset = offsets.get(tail)?.bytes(); + self.0.size.bytes().checked_sub(offset)?.checked_sub(tail_field_size) + } + } + } + + pub fn largest_padding( + &self, + field_size: &mut impl FnMut(usize) -> Option, + ) -> Option { + match self.0.fields { + layout::FieldsShape::Primitive => None, + layout::FieldsShape::Union(_) => None, + layout::FieldsShape::Array { stride: _, count: 0 } => None, + layout::FieldsShape::Array { stride, .. } => { + let size = field_size(0)?; + stride.bytes().checked_sub(size) + } + layout::FieldsShape::Arbitrary { ref offsets, ref memory_index } => { + let mut reverse_index = vec![None; memory_index.len()]; + for (src, (mem, offset)) in memory_index.iter().zip(offsets.iter()).enumerate() { + reverse_index[*mem as usize] = Some((src, offset.bytes())); + } + if reverse_index.iter().any(|it| it.is_none()) { + stdx::never!(); + return None; + } + reverse_index + .into_iter() + .flatten() + .chain(std::iter::once((0, self.0.size.bytes()))) + .tuple_windows() + .filter_map(|((i, start), (_, end))| { + let size = field_size(i)?; + end.checked_sub(start)?.checked_sub(size) + }) + .max() + } + } + } + pub fn enum_tag_size(&self) -> Option { let tag_size = if let layout::Variants::Multiple { tag, tag_encoding, .. } = &self.0.variants { diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 873e31b4a337..8bb1c708e25d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -58,6 +58,7 @@ pub struct MemoryLayoutHoverConfig { pub size: Option, pub offset: Option, pub alignment: Option, + pub padding: Option, pub niches: bool, } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index ad720c8a6274..c24864a18bdf 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -630,27 +630,57 @@ pub(super) fn definition( } }, |_| None, + |_| None, + ), + Definition::Adt(it @ Adt::Struct(strukt)) => render_memory_layout( + config.memory_layout, + || it.layout(db), + |_| None, + |layout| { + let mut field_size = + |i: usize| Some(strukt.fields(db).get(i)?.layout(db).ok()?.size()); + if strukt.repr(db).is_some_and(|it| it.inhibit_struct_field_reordering()) { + Some(("tail padding", layout.tail_padding(&mut field_size)?)) + } else { + Some(("largest padding", layout.largest_padding(&mut field_size)?)) + } + }, + |_| None, + ), + Definition::Adt(it) => render_memory_layout( + config.memory_layout, + || it.layout(db), + |_| None, + |_| None, + |_| None, ), - Definition::Adt(it) => { - render_memory_layout(config.memory_layout, || it.layout(db), |_| None, |_| None) - } Definition::Variant(it) => render_memory_layout( config.memory_layout, || it.layout(db), |_| None, + |_| None, |layout| layout.enum_tag_size(), ), - Definition::TypeAlias(it) => { - render_memory_layout(config.memory_layout, || it.ty(db).layout(db), |_| None, |_| None) - } - Definition::Local(it) => { - render_memory_layout(config.memory_layout, || it.ty(db).layout(db), |_| None, |_| None) - } + Definition::TypeAlias(it) => render_memory_layout( + config.memory_layout, + || it.ty(db).layout(db), + |_| None, + |_| None, + |_| None, + ), + Definition::Local(it) => render_memory_layout( + config.memory_layout, + || it.ty(db).layout(db), + |_| None, + |_| None, + |_| None, + ), Definition::SelfType(it) => render_memory_layout( config.memory_layout, || it.self_ty(db).layout(db), |_| None, |_| None, + |_| None, ), _ => None, }; @@ -1055,9 +1085,13 @@ fn closure_ty( if let Some(trait_) = c.fn_trait(sema.db).get_id(sema.db, original.krate(sema.db).into()) { push_new_def(hir::Trait::from(trait_).into()) } - if let Some(layout) = - render_memory_layout(config.memory_layout, || original.layout(sema.db), |_| None, |_| None) - { + if let Some(layout) = render_memory_layout( + config.memory_layout, + || original.layout(sema.db), + |_| None, + |_| None, + |_| None, + ) { format_to!(markup, "\n___\n{layout}"); } format_to!(markup, "{adjusted}\n\n## Captures\n{}", captures_rendered,); @@ -1142,6 +1176,7 @@ fn render_memory_layout( config: Option, layout: impl FnOnce() -> Result, offset: impl FnOnce(&Layout) -> Option, + padding: impl FnOnce(&Layout) -> Option<(&str, u64)>, tag: impl FnOnce(&Layout) -> Option, ) -> Option { let config = config?; @@ -1199,6 +1234,23 @@ fn render_memory_layout( } } + if let Some(render) = config.padding { + if let Some((padding_name, padding)) = padding(&layout) { + format_to!(label, "{padding_name} = "); + match render { + MemoryLayoutHoverRenderKind::Decimal => format_to!(label, "{padding}"), + MemoryLayoutHoverRenderKind::Hexadecimal => format_to!(label, "{padding:#X}"), + MemoryLayoutHoverRenderKind::Both if padding >= 10 => { + format_to!(label, "{padding} ({padding:#X})") + } + MemoryLayoutHoverRenderKind::Both => { + format_to!(label, "{padding}") + } + } + format_to!(label, ", "); + } + } + if config.niches { if let Some(niches) = layout.niches() { if niches > 1024 { diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index 06ca24c3ec35..a281a491525c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -12,6 +12,7 @@ const HOVER_BASE_CONFIG: HoverConfig = HoverConfig { size: Some(MemoryLayoutHoverRenderKind::Both), offset: Some(MemoryLayoutHoverRenderKind::Both), alignment: Some(MemoryLayoutHoverRenderKind::Both), + padding: Some(MemoryLayoutHoverRenderKind::Both), niches: true, }), documentation: true, @@ -933,7 +934,7 @@ struct Foo$0(pub u32) where u32: Copy; --- - size = 4, align = 4, no Drop + size = 4, align = 4, largest padding = 0, no Drop "#]], ); } @@ -959,7 +960,7 @@ struct Foo$0 { field: u32 } --- - size = 4, align = 4, no Drop + size = 4, align = 4, largest padding = 0, no Drop "#]], ); check( @@ -984,7 +985,7 @@ struct Foo$0 where u32: Copy { field: u32 } --- - size = 4, align = 4, no Drop + size = 4, align = 4, largest padding = 0, no Drop "#]], ); } @@ -1013,7 +1014,7 @@ fn hover_record_struct_limit() { --- - size = 12 (0xC), align = 4, no Drop + size = 12 (0xC), align = 4, largest padding = 0, no Drop "#]], ); check_hover_fields_limit( @@ -1036,7 +1037,7 @@ fn hover_record_struct_limit() { --- - size = 4, align = 4, no Drop + size = 4, align = 4, largest padding = 0, no Drop "#]], ); check_hover_fields_limit( @@ -1062,7 +1063,7 @@ fn hover_record_struct_limit() { --- - size = 16 (0x10), align = 4, no Drop + size = 16 (0x10), align = 4, largest padding = 0, no Drop "#]], ); check_hover_fields_limit( @@ -1083,7 +1084,7 @@ fn hover_record_struct_limit() { --- - size = 12 (0xC), align = 4, no Drop + size = 12 (0xC), align = 4, largest padding = 0, no Drop "#]], ); check_hover_fields_limit( @@ -1104,7 +1105,7 @@ fn hover_record_struct_limit() { --- - size = 12 (0xC), align = 4, no Drop + size = 12 (0xC), align = 4, largest padding = 0, no Drop "#]], ); @@ -3114,7 +3115,7 @@ struct S$0(core::marker::PhantomData); --- - size = 0, align = 1, no Drop + size = 0, align = 1, largest padding = 0, no Drop "#]], ); } @@ -3147,6 +3148,111 @@ fn test_hover_layout_of_enum() { ); } +#[test] +fn test_hover_layout_padding_info() { + check( + r#"struct $0Foo { + x: bool, + y: i64, + z: u32, + }"#, + expect![[r#" + *Foo* + + ```rust + ra_test_fixture + ``` + + ```rust + struct Foo { + x: bool, + y: i64, + z: u32, + } + ``` + + --- + + size = 16 (0x10), align = 8, largest padding = 3, niches = 254, no Drop + "#]], + ); + + check( + r#"#[repr(align(32))] + struct $0Foo { + x: bool, + y: i64, + z: u32, + }"#, + expect![[r#" + *Foo* + + ```rust + ra_test_fixture + ``` + + ```rust + struct Foo { + x: bool, + y: i64, + z: u32, + } + ``` + + --- + + size = 32 (0x20), align = 32 (0x20), largest padding = 19 (0x13), niches = 254, no Drop + "#]], + ); + + check( + r#"#[repr(C)] + struct $0Foo { + x: bool, + y: i64, + z: u32, + }"#, + expect![[r#" + *Foo* + + ```rust + ra_test_fixture + ``` + + ```rust + struct Foo { + x: bool, + y: i64, + z: u32, + } + ``` + + --- + + size = 24 (0x18), align = 8, tail padding = 4, niches = 254, no Drop + "#]], + ); + + check( + r#"struct $0Foo(i16, u128, u64)"#, + expect![[r#" + *Foo* + + ```rust + ra_test_fixture + ``` + + ```rust + struct Foo(i16, u128, u64) + ``` + + --- + + size = 32 (0x20), align = 8, largest padding = 6, no Drop + "#]], + ); +} + #[test] fn test_hover_no_memory_layout() { check_hover_no_memory_layout( @@ -9198,7 +9304,7 @@ struct Pedro$0<'a> { --- - size = 16 (0x10), align = 8, niches = 1, no Drop + size = 16 (0x10), align = 8, largest padding = 0, niches = 1, no Drop "#]], ) } @@ -10559,7 +10665,7 @@ struct DropField$0 { --- - size = 4, align = 4, needs Drop + size = 4, align = 4, largest padding = 0, needs Drop "#]], ); check( diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index f7158235ca4c..d1ca8c1a91a3 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -149,6 +149,8 @@ config_data! { hover_memoryLayout_niches: Option = Some(false), /// How to render the offset information in a memory layout hover. hover_memoryLayout_offset: Option = Some(MemoryLayoutHoverRenderKindDef::Hexadecimal), + /// How to render the padding information in a memory layout hover. + hover_memoryLayout_padding: Option = None, /// How to render the size information in a memory layout hover. hover_memoryLayout_size: Option = Some(MemoryLayoutHoverRenderKindDef::Both), @@ -1635,6 +1637,7 @@ impl Config { size: self.hover_memoryLayout_size().map(mem_kind), offset: self.hover_memoryLayout_offset().map(mem_kind), alignment: self.hover_memoryLayout_alignment().map(mem_kind), + padding: self.hover_memoryLayout_padding().map(mem_kind), niches: self.hover_memoryLayout_niches().unwrap_or_default(), }), documentation: self.hover_documentation_enable().to_owned(), diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md index de1d0ea4a359..0e07dadfb7c9 100644 --- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md +++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md @@ -763,6 +763,13 @@ Default: `"hexadecimal"` How to render the offset information in a memory layout hover. +## rust-analyzer.hover.memoryLayout.padding {#hover.memoryLayout.padding} + +Default: `null` + +How to render the padding information in a memory layout hover. + + ## rust-analyzer.hover.memoryLayout.size {#hover.memoryLayout.size} Default: `"both"` diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 88a90aad8c9f..c8c36cd85c8e 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -1779,6 +1779,33 @@ } } }, + { + "title": "hover", + "properties": { + "rust-analyzer.hover.memoryLayout.padding": { + "markdownDescription": "How to render the padding information in a memory layout hover.", + "default": null, + "anyOf": [ + { + "type": "null" + }, + { + "type": "string", + "enum": [ + "both", + "decimal", + "hexadecimal" + ], + "enumDescriptions": [ + "Render as 12 (0xC)", + "Render as 12", + "Render as 0xC" + ] + } + ] + } + } + }, { "title": "hover", "properties": { From 4c4a40f6dfa7630a8817748a687cfdd1335a7358 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 28 May 2025 08:20:30 +1000 Subject: [PATCH 61/80] Reorder `ast::ItemKind::{Struct,Enum,Union}` fields. So they match the order of the parts in the source code, e.g.: ``` struct Foo { t: T, u: U } <-><----> <------------> / | \ ident generics variant_data ``` --- compiler/rustc_ast/src/ast.rs | 20 +++++++++---------- compiler/rustc_ast/src/visit.rs | 6 +++--- compiler/rustc_ast_lowering/src/item.rs | 6 +++--- .../rustc_ast_passes/src/ast_validation.rs | 6 +++--- .../rustc_ast_pretty/src/pprust/state/item.rs | 8 ++++---- .../src/deriving/clone.rs | 4 ++-- .../src/deriving/cmp/partial_ord.rs | 2 +- .../src/deriving/coerce_pointee.rs | 2 +- .../src/deriving/generic/mod.rs | 6 +++--- compiler/rustc_expand/src/base.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 6 +++--- .../rustc_resolve/src/build_reduced_graph.rs | 4 ++-- compiler/rustc_resolve/src/def_collector.rs | 4 ++-- .../src/effective_visibilities.rs | 4 ++-- compiler/rustc_resolve/src/late.rs | 12 +++++------ .../src/field_scoped_visibility_modifiers.rs | 2 +- .../clippy_lints/src/partial_pub_fields.rs | 2 +- .../clippy/clippy_utils/src/ast_utils/mod.rs | 8 ++++---- src/tools/rustfmt/src/items.rs | 4 ++-- src/tools/rustfmt/src/visitor.rs | 2 +- 20 files changed, 54 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index a16219361c05..2ececee87510 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3417,9 +3417,9 @@ impl Item { ItemKind::Fn(i) => Some(&i.generics), ItemKind::TyAlias(i) => Some(&i.generics), ItemKind::TraitAlias(_, generics, _) - | ItemKind::Enum(_, _, generics) - | ItemKind::Struct(_, _, generics) - | ItemKind::Union(_, _, generics) => Some(&generics), + | ItemKind::Enum(_, generics, _) + | ItemKind::Struct(_, generics, _) + | ItemKind::Union(_, generics, _) => Some(&generics), ItemKind::Trait(i) => Some(&i.generics), ItemKind::Impl(i) => Some(&i.generics), } @@ -3663,15 +3663,15 @@ pub enum ItemKind { /// An enum definition (`enum`). /// /// E.g., `enum Foo { C, D }`. - Enum(Ident, EnumDef, Generics), + Enum(Ident, Generics, EnumDef), /// A struct definition (`struct`). /// /// E.g., `struct Foo { x: A }`. - Struct(Ident, VariantData, Generics), + Struct(Ident, Generics, VariantData), /// A union definition (`union`). /// /// E.g., `union Foo { x: A, y: B }`. - Union(Ident, VariantData, Generics), + Union(Ident, Generics, VariantData), /// A trait declaration (`trait`). /// /// E.g., `trait Foo { .. }`, `trait Foo { .. }` or `auto trait Foo {}`. @@ -3688,10 +3688,8 @@ pub enum ItemKind { /// /// E.g., `foo!(..)`. MacCall(P), - /// A macro definition. MacroDef(Ident, MacroDef), - /// A single delegation item (`reuse`). /// /// E.g. `reuse ::name { target_expr_template }`. @@ -3767,9 +3765,9 @@ impl ItemKind { Self::Fn(box Fn { generics, .. }) | Self::TyAlias(box TyAlias { generics, .. }) | Self::Const(box ConstItem { generics, .. }) - | Self::Enum(_, _, generics) - | Self::Struct(_, _, generics) - | Self::Union(_, _, generics) + | Self::Enum(_, generics, _) + | Self::Struct(_, generics, _) + | Self::Union(_, generics, _) | Self::Trait(box Trait { generics, .. }) | Self::TraitAlias(_, generics, _) | Self::Impl(box Impl { generics, .. }) => Some(generics), diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index bf5c402e52e5..1cc11b58dd97 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -508,7 +508,7 @@ macro_rules! common_visitor_and_walkers { )? $(>::Result::output())? } - ItemKind::Enum(ident, enum_definition, generics) => { + ItemKind::Enum(ident, generics, enum_definition) => { try_visit!(vis.visit_ident(ident)); try_visit!(vis.visit_generics(generics)); $(${ignore($mut)} @@ -516,8 +516,8 @@ macro_rules! common_visitor_and_walkers { )? $(${ignore($lt)}vis.visit_enum_def(enum_definition))? } - ItemKind::Struct(ident, variant_data, generics) - | ItemKind::Union(ident, variant_data, generics) => { + ItemKind::Struct(ident, generics, variant_data) + | ItemKind::Union(ident, generics, variant_data) => { try_visit!(vis.visit_ident(ident)); try_visit!(vis.visit_generics(generics)); vis.visit_variant_data(variant_data) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index e98d6c50ee79..7f7d45790ee2 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -306,7 +306,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::ItemKind::TyAlias(ident, ty, generics) } - ItemKind::Enum(ident, enum_definition, generics) => { + ItemKind::Enum(ident, generics, enum_definition) => { let ident = self.lower_ident(*ident); let (generics, variants) = self.lower_generics( generics, @@ -320,7 +320,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::ItemKind::Enum(ident, hir::EnumDef { variants }, generics) } - ItemKind::Struct(ident, struct_def, generics) => { + ItemKind::Struct(ident, generics, struct_def) => { let ident = self.lower_ident(*ident); let (generics, struct_def) = self.lower_generics( generics, @@ -330,7 +330,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::ItemKind::Struct(ident, struct_def, generics) } - ItemKind::Union(ident, vdata, generics) => { + ItemKind::Union(ident, generics, vdata) => { let ident = self.lower_ident(*ident); let (generics, vdata) = self.lower_generics( generics, diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index cbf4f2f5eb2b..d6fe04d2994b 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1010,7 +1010,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }); self.extern_mod_span = old_item; } - ItemKind::Enum(_, def, _) => { + ItemKind::Enum(_, _, def) => { for variant in &def.variants { self.visibility_not_permitted( &variant.vis, @@ -1061,7 +1061,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } visit::walk_item(self, item) } - ItemKind::Struct(ident, vdata, generics) => match vdata { + ItemKind::Struct(ident, generics, vdata) => match vdata { VariantData::Struct { fields, .. } => { self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); self.visit_generics(generics); @@ -1070,7 +1070,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } _ => visit::walk_item(self, item), }, - ItemKind::Union(ident, vdata, generics) => { + ItemKind::Union(ident, generics, vdata) => { if vdata.fields().is_empty() { self.dcx().emit_err(errors::FieldlessUnion { span: item.span }); } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 70cf2f2a4598..3638eb31c618 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -298,14 +298,14 @@ impl<'a> State<'a> { *defaultness, ); } - ast::ItemKind::Enum(ident, enum_definition, params) => { - self.print_enum_def(enum_definition, params, *ident, item.span, &item.vis); + ast::ItemKind::Enum(ident, generics, enum_definition) => { + self.print_enum_def(enum_definition, generics, *ident, item.span, &item.vis); } - ast::ItemKind::Struct(ident, struct_def, generics) => { + ast::ItemKind::Struct(ident, generics, struct_def) => { let (cb, ib) = self.head(visibility_qualified(&item.vis, "struct")); self.print_struct(struct_def, generics, *ident, item.span, true, cb, ib); } - ast::ItemKind::Union(ident, struct_def, generics) => { + ast::ItemKind::Union(ident, generics, struct_def) => { let (cb, ib) = self.head(visibility_qualified(&item.vis, "union")); self.print_struct(struct_def, generics, *ident, item.span, true, cb, ib); } diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 44cf215c6622..69f8c273797e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -34,8 +34,8 @@ pub(crate) fn expand_deriving_clone( let is_simple; match item { Annotatable::Item(annitem) => match &annitem.kind { - ItemKind::Struct(_, _, Generics { params, .. }) - | ItemKind::Enum(_, _, Generics { params, .. }) => { + ItemKind::Struct(_, Generics { params, .. }, _) + | ItemKind::Enum(_, Generics { params, .. }, _) => { let container_id = cx.current_expansion.id.expn_data().parent.expect_local(); let has_derive_copy = cx.resolver.has_derive_copy(container_id); if has_derive_copy diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index aa01da3151eb..0a076dd670b3 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -21,7 +21,7 @@ pub(crate) fn expand_deriving_partial_ord( // Order in which to perform matching let discr_then_data = if let Annotatable::Item(item) = item - && let ItemKind::Enum(_, def, _) = &item.kind + && let ItemKind::Enum(_, _, def) = &item.kind { let dataful: Vec = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect(); match dataful.iter().filter(|&&b| b).count() { diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index 446d8afeedd7..0794192621a9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -30,7 +30,7 @@ pub(crate) fn expand_deriving_coerce_pointee( item.visit_with(&mut DetectNonGenericPointeeAttr { cx }); let (name_ident, generics) = if let Annotatable::Item(aitem) = item - && let ItemKind::Struct(ident, struct_data, g) = &aitem.kind + && let ItemKind::Struct(ident, g, struct_data) = &aitem.kind { if !matches!( struct_data, diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 9aa53f9e4f73..f1bef526c108 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -488,7 +488,7 @@ impl<'a> TraitDef<'a> { ); let newitem = match &item.kind { - ast::ItemKind::Struct(ident, struct_def, generics) => self.expand_struct_def( + ast::ItemKind::Struct(ident, generics, struct_def) => self.expand_struct_def( cx, struct_def, *ident, @@ -496,7 +496,7 @@ impl<'a> TraitDef<'a> { from_scratch, is_packed, ), - ast::ItemKind::Enum(ident, enum_def, generics) => { + ast::ItemKind::Enum(ident, generics, enum_def) => { // We ignore `is_packed` here, because `repr(packed)` // enums cause an error later on. // @@ -504,7 +504,7 @@ impl<'a> TraitDef<'a> { // downstream in blatantly illegal code, so it is fine. self.expand_enum_def(cx, enum_def, *ident, generics, from_scratch) } - ast::ItemKind::Union(ident, struct_def, generics) => { + ast::ItemKind::Union(ident, generics, struct_def) => { if self.supports_unions { self.expand_struct_def( cx, diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 55751aa49089..2accfba383e6 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1424,7 +1424,7 @@ pub fn parse_macro_name_and_helper_attrs( /// See #73345 and #83125 for more details. /// FIXME(#73933): Remove this eventually. fn pretty_printing_compatibility_hack(item: &Item, psess: &ParseSess) { - if let ast::ItemKind::Enum(ident, enum_def, _) = &item.kind + if let ast::ItemKind::Enum(ident, _, enum_def) = &item.kind && ident.name == sym::ProceduralMasqueradeDummyType && let [variant] = &*enum_def.variants && variant.ident.name == sym::Input diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index babc55ccc0f9..c7b0eb11e5a0 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1577,7 +1577,7 @@ impl<'a> Parser<'a> { }; let enum_definition = EnumDef { variants: variants.into_iter().flatten().collect() }; - Ok(ItemKind::Enum(ident, enum_definition, generics)) + Ok(ItemKind::Enum(ident, generics, enum_definition)) } fn parse_enum_variant(&mut self, span: Span) -> PResult<'a, Option> { @@ -1732,7 +1732,7 @@ impl<'a> Parser<'a> { return Err(self.dcx().create_err(err)); }; - Ok(ItemKind::Struct(ident, vdata, generics)) + Ok(ItemKind::Struct(ident, generics, vdata)) } /// Parses `union Foo { ... }`. @@ -1764,7 +1764,7 @@ impl<'a> Parser<'a> { return Err(err); }; - Ok(ItemKind::Union(ident, vdata, generics)) + Ok(ItemKind::Union(ident, generics, vdata)) } /// This function parses the fields of record structs: diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 3460c53782f3..c30ed781f35f 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -823,7 +823,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } // These items live in both the type and value namespaces. - ItemKind::Struct(ident, ref vdata, _) => { + ItemKind::Struct(ident, _, ref vdata) => { self.build_reduced_graph_for_struct_variant( vdata.fields(), ident, @@ -874,7 +874,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } } - ItemKind::Union(ident, ref vdata, _) => { + ItemKind::Union(ident, _, ref vdata) => { self.build_reduced_graph_for_struct_variant( vdata.fields(), ident, diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 13dfb59f27fc..25485be56226 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -162,8 +162,8 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { self.with_parent(def_id, |this| { this.with_impl_trait(ImplTraitContext::Existential, |this| { match i.kind { - ItemKind::Struct(_, ref struct_def, _) - | ItemKind::Union(_, ref struct_def, _) => { + ItemKind::Struct(_, _, ref struct_def) + | ItemKind::Union(_, _, ref struct_def) => { // If this is a unit or tuple-like struct, register the constructor. if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(struct_def) { this.create_def( diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index a5ca4565d7b4..5de80de3f8d3 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -252,7 +252,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> self.current_private_vis = prev_private_vis; } - ast::ItemKind::Enum(_, EnumDef { ref variants }, _) => { + ast::ItemKind::Enum(_, _, EnumDef { ref variants }) => { self.set_bindings_effective_visibilities(def_id); for variant in variants { let variant_def_id = self.r.local_def_id(variant.id); @@ -262,7 +262,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> } } - ast::ItemKind::Struct(_, ref def, _) | ast::ItemKind::Union(_, ref def, _) => { + ast::ItemKind::Struct(_, _, ref def) | ast::ItemKind::Union(_, _, ref def) => { for field in def.fields() { self.update_field(self.r.local_def_id(field.id), def_id); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index fd977a8eb6c0..4cfa079e49b4 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2694,9 +2694,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.resolve_define_opaques(define_opaque); } - ItemKind::Enum(_, _, ref generics) - | ItemKind::Struct(_, _, ref generics) - | ItemKind::Union(_, _, ref generics) => { + ItemKind::Enum(_, ref generics, _) + | ItemKind::Struct(_, ref generics, _) + | ItemKind::Union(_, ref generics, _) => { self.resolve_adt(item, generics); } @@ -5243,9 +5243,9 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { ItemKind::TyAlias(box TyAlias { generics, .. }) | ItemKind::Const(box ConstItem { generics, .. }) | ItemKind::Fn(box Fn { generics, .. }) - | ItemKind::Enum(_, _, generics) - | ItemKind::Struct(_, _, generics) - | ItemKind::Union(_, _, generics) + | ItemKind::Enum(_, generics, _) + | ItemKind::Struct(_, generics, _) + | ItemKind::Union(_, generics, _) | ItemKind::Impl(box Impl { generics, .. }) | ItemKind::Trait(box Trait { generics, .. }) | ItemKind::TraitAlias(_, generics, _) => { diff --git a/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs b/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs index aae8291905d3..dfb0b4f103c5 100644 --- a/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs +++ b/src/tools/clippy/clippy_lints/src/field_scoped_visibility_modifiers.rs @@ -51,7 +51,7 @@ declare_lint_pass!(FieldScopedVisibilityModifiers => [FIELD_SCOPED_VISIBILITY_MO impl EarlyLintPass for FieldScopedVisibilityModifiers { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - let ItemKind::Struct(_, ref st, _) = item.kind else { + let ItemKind::Struct(_, _, ref st) = item.kind else { return; }; for field in st.fields() { diff --git a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs index cda752d003fa..65e93af9420d 100644 --- a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs +++ b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs @@ -41,7 +41,7 @@ declare_lint_pass!(PartialPubFields => [PARTIAL_PUB_FIELDS]); impl EarlyLintPass for PartialPubFields { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - let ItemKind::Struct(_, ref st, _) = item.kind else { + let ItemKind::Struct(_, _, ref st) = item.kind else { return; }; diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 8996b694ed8f..a0503a699e69 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -436,11 +436,11 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { && over(lb, rb, eq_generic_bound) && both(lt.as_ref(), rt.as_ref(), |l, r| eq_ty(l, r)) }, - (Enum(li, le, lg), Enum(ri, re, rg)) => { - eq_id(*li, *ri) && over(&le.variants, &re.variants, eq_variant) && eq_generics(lg, rg) + (Enum(li, lg, le), Enum(ri, rg, re)) => { + eq_id(*li, *ri) && eq_generics(lg, rg) && over(&le.variants, &re.variants, eq_variant) }, - (Struct(li, lv, lg), Struct(ri, rv, rg)) | (Union(li, lv, lg), Union(ri, rv, rg)) => { - eq_id(*li, *ri) && eq_variant_data(lv, rv) && eq_generics(lg, rg) + (Struct(li, lg, lv), Struct(ri, rg, rv)) | (Union(li, lg, lv), Union(ri, rg, rv)) => { + eq_id(*li, *ri) && eq_generics(lg, rg) && eq_variant_data(lv, rv) }, ( Trait(box ast::Trait { diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index e79b7803c607..1a3897b51cb8 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1110,10 +1110,10 @@ impl<'a> StructParts<'a> { pub(crate) fn from_item(item: &'a ast::Item) -> Self { let (prefix, def, ident, generics) = match item.kind { - ast::ItemKind::Struct(ident, ref def, ref generics) => { + ast::ItemKind::Struct(ident, ref generics, ref def) => { ("struct ", def, ident, generics) } - ast::ItemKind::Union(ident, ref def, ref generics) => ("union ", def, ident, generics), + ast::ItemKind::Union(ident, ref generics, ref def) => ("union ", def, ident, generics), _ => unreachable!(), }; StructParts { diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs index 16d1f5105d5f..f6a9a3f2cd17 100644 --- a/src/tools/rustfmt/src/visitor.rs +++ b/src/tools/rustfmt/src/visitor.rs @@ -521,7 +521,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { ast::ItemKind::Struct(..) | ast::ItemKind::Union(..) => { self.visit_struct(&StructParts::from_item(item)); } - ast::ItemKind::Enum(ident, ref def, ref generics) => { + ast::ItemKind::Enum(ident, ref generics, ref def) => { self.format_missing_with_indent(source!(self, item.span).lo()); self.visit_enum(ident, &item.vis, def, generics, item.span); self.last_pos = source!(self, item.span).hi(); From 2a9363e59389dcfcb28146d4c8f4e4ce179ded77 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 May 2025 08:37:45 +0200 Subject: [PATCH 62/80] coretests: simplify test_float macro to derive more things from the type name --- library/coretests/tests/num/mod.rs | 236 +++++++++++++---------------- 1 file changed, 102 insertions(+), 134 deletions(-) diff --git a/library/coretests/tests/num/mod.rs b/library/coretests/tests/num/mod.rs index a6b75f702660..cdde5b883aa9 100644 --- a/library/coretests/tests/num/mod.rs +++ b/library/coretests/tests/num/mod.rs @@ -732,7 +732,7 @@ assume_usize_width! { } macro_rules! test_float { - ($modname: ident, $fassert: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr, $min: expr, $max: expr, $min_pos: expr, $max_exp:expr) => { + ($modname: ident, $fassert: ident, $fty: ty) => { mod $modname { #[test] fn min() { @@ -747,19 +747,19 @@ macro_rules! test_float { $fassert!((-0.0 as $fty).min(9.0), -0.0); $fassert!((-0.0 as $fty).min(9.0).is_sign_negative()); $fassert!((-0.0 as $fty).min(-9.0), -9.0); - $fassert!(($inf as $fty).min(9.0), 9.0); - $fassert!((9.0 as $fty).min($inf), 9.0); - $fassert!(($inf as $fty).min(-9.0), -9.0); - $fassert!((-9.0 as $fty).min($inf), -9.0); - $fassert!(($neginf as $fty).min(9.0), $neginf); - $fassert!((9.0 as $fty).min($neginf), $neginf); - $fassert!(($neginf as $fty).min(-9.0), $neginf); - $fassert!((-9.0 as $fty).min($neginf), $neginf); - $fassert!(($nan as $fty).min(9.0), 9.0); - $fassert!(($nan as $fty).min(-9.0), -9.0); - $fassert!((9.0 as $fty).min($nan), 9.0); - $fassert!((-9.0 as $fty).min($nan), -9.0); - $fassert!(($nan as $fty).min($nan).is_nan()); + $fassert!((<$fty>::INFINITY as $fty).min(9.0), 9.0); + $fassert!((9.0 as $fty).min(<$fty>::INFINITY), 9.0); + $fassert!((<$fty>::INFINITY as $fty).min(-9.0), -9.0); + $fassert!((-9.0 as $fty).min(<$fty>::INFINITY), -9.0); + $fassert!((<$fty>::NEG_INFINITY as $fty).min(9.0), <$fty>::NEG_INFINITY); + $fassert!((9.0 as $fty).min(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); + $fassert!((<$fty>::NEG_INFINITY as $fty).min(-9.0), <$fty>::NEG_INFINITY); + $fassert!((-9.0 as $fty).min(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); + $fassert!((<$fty>::NAN as $fty).min(9.0), 9.0); + $fassert!((<$fty>::NAN as $fty).min(-9.0), -9.0); + $fassert!((9.0 as $fty).min(<$fty>::NAN), 9.0); + $fassert!((-9.0 as $fty).min(<$fty>::NAN), -9.0); + $fassert!((<$fty>::NAN as $fty).min(<$fty>::NAN).is_nan()); } #[test] fn max() { @@ -777,19 +777,19 @@ macro_rules! test_float { $fassert!((0.0 as $fty).max(-9.0).is_sign_positive()); $fassert!((-0.0 as $fty).max(-9.0), -0.0); $fassert!((-0.0 as $fty).max(-9.0).is_sign_negative()); - $fassert!(($inf as $fty).max(9.0), $inf); - $fassert!((9.0 as $fty).max($inf), $inf); - $fassert!(($inf as $fty).max(-9.0), $inf); - $fassert!((-9.0 as $fty).max($inf), $inf); - $fassert!(($neginf as $fty).max(9.0), 9.0); - $fassert!((9.0 as $fty).max($neginf), 9.0); - $fassert!(($neginf as $fty).max(-9.0), -9.0); - $fassert!((-9.0 as $fty).max($neginf), -9.0); - $fassert!(($nan as $fty).max(9.0), 9.0); - $fassert!(($nan as $fty).max(-9.0), -9.0); - $fassert!((9.0 as $fty).max($nan), 9.0); - $fassert!((-9.0 as $fty).max($nan), -9.0); - $fassert!(($nan as $fty).max($nan).is_nan()); + $fassert!((<$fty>::INFINITY as $fty).max(9.0), <$fty>::INFINITY); + $fassert!((9.0 as $fty).max(<$fty>::INFINITY), <$fty>::INFINITY); + $fassert!((<$fty>::INFINITY as $fty).max(-9.0), <$fty>::INFINITY); + $fassert!((-9.0 as $fty).max(<$fty>::INFINITY), <$fty>::INFINITY); + $fassert!((<$fty>::NEG_INFINITY as $fty).max(9.0), 9.0); + $fassert!((9.0 as $fty).max(<$fty>::NEG_INFINITY), 9.0); + $fassert!((<$fty>::NEG_INFINITY as $fty).max(-9.0), -9.0); + $fassert!((-9.0 as $fty).max(<$fty>::NEG_INFINITY), -9.0); + $fassert!((<$fty>::NAN as $fty).max(9.0), 9.0); + $fassert!((<$fty>::NAN as $fty).max(-9.0), -9.0); + $fassert!((9.0 as $fty).max(<$fty>::NAN), 9.0); + $fassert!((-9.0 as $fty).max(<$fty>::NAN), -9.0); + $fassert!((<$fty>::NAN as $fty).max(<$fty>::NAN).is_nan()); } #[test] fn minimum() { @@ -806,19 +806,19 @@ macro_rules! test_float { $fassert!((-0.0 as $fty).minimum(9.0), -0.0); $fassert!((-0.0 as $fty).minimum(9.0).is_sign_negative()); $fassert!((-0.0 as $fty).minimum(-9.0), -9.0); - $fassert!(($inf as $fty).minimum(9.0), 9.0); - $fassert!((9.0 as $fty).minimum($inf), 9.0); - $fassert!(($inf as $fty).minimum(-9.0), -9.0); - $fassert!((-9.0 as $fty).minimum($inf), -9.0); - $fassert!(($neginf as $fty).minimum(9.0), $neginf); - $fassert!((9.0 as $fty).minimum($neginf), $neginf); - $fassert!(($neginf as $fty).minimum(-9.0), $neginf); - $fassert!((-9.0 as $fty).minimum($neginf), $neginf); - $fassert!(($nan as $fty).minimum(9.0).is_nan()); - $fassert!(($nan as $fty).minimum(-9.0).is_nan()); - $fassert!((9.0 as $fty).minimum($nan).is_nan()); - $fassert!((-9.0 as $fty).minimum($nan).is_nan()); - $fassert!(($nan as $fty).minimum($nan).is_nan()); + $fassert!((<$fty>::INFINITY as $fty).minimum(9.0), 9.0); + $fassert!((9.0 as $fty).minimum(<$fty>::INFINITY), 9.0); + $fassert!((<$fty>::INFINITY as $fty).minimum(-9.0), -9.0); + $fassert!((-9.0 as $fty).minimum(<$fty>::INFINITY), -9.0); + $fassert!((<$fty>::NEG_INFINITY as $fty).minimum(9.0), <$fty>::NEG_INFINITY); + $fassert!((9.0 as $fty).minimum(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); + $fassert!((<$fty>::NEG_INFINITY as $fty).minimum(-9.0), <$fty>::NEG_INFINITY); + $fassert!((-9.0 as $fty).minimum(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); + $fassert!((<$fty>::NAN as $fty).minimum(9.0).is_nan()); + $fassert!((<$fty>::NAN as $fty).minimum(-9.0).is_nan()); + $fassert!((9.0 as $fty).minimum(<$fty>::NAN).is_nan()); + $fassert!((-9.0 as $fty).minimum(<$fty>::NAN).is_nan()); + $fassert!((<$fty>::NAN as $fty).minimum(<$fty>::NAN).is_nan()); } #[test] fn maximum() { @@ -838,19 +838,19 @@ macro_rules! test_float { $fassert!((0.0 as $fty).maximum(-9.0).is_sign_positive()); $fassert!((-0.0 as $fty).maximum(-9.0), -0.0); $fassert!((-0.0 as $fty).maximum(-9.0).is_sign_negative()); - $fassert!(($inf as $fty).maximum(9.0), $inf); - $fassert!((9.0 as $fty).maximum($inf), $inf); - $fassert!(($inf as $fty).maximum(-9.0), $inf); - $fassert!((-9.0 as $fty).maximum($inf), $inf); - $fassert!(($neginf as $fty).maximum(9.0), 9.0); - $fassert!((9.0 as $fty).maximum($neginf), 9.0); - $fassert!(($neginf as $fty).maximum(-9.0), -9.0); - $fassert!((-9.0 as $fty).maximum($neginf), -9.0); - $fassert!(($nan as $fty).maximum(9.0).is_nan()); - $fassert!(($nan as $fty).maximum(-9.0).is_nan()); - $fassert!((9.0 as $fty).maximum($nan).is_nan()); - $fassert!((-9.0 as $fty).maximum($nan).is_nan()); - $fassert!(($nan as $fty).maximum($nan).is_nan()); + $fassert!((<$fty>::INFINITY as $fty).maximum(9.0), <$fty>::INFINITY); + $fassert!((9.0 as $fty).maximum(<$fty>::INFINITY), <$fty>::INFINITY); + $fassert!((<$fty>::INFINITY as $fty).maximum(-9.0), <$fty>::INFINITY); + $fassert!((-9.0 as $fty).maximum(<$fty>::INFINITY), <$fty>::INFINITY); + $fassert!((<$fty>::NEG_INFINITY as $fty).maximum(9.0), 9.0); + $fassert!((9.0 as $fty).maximum(<$fty>::NEG_INFINITY), 9.0); + $fassert!((<$fty>::NEG_INFINITY as $fty).maximum(-9.0), -9.0); + $fassert!((-9.0 as $fty).maximum(<$fty>::NEG_INFINITY), -9.0); + $fassert!((<$fty>::NAN as $fty).maximum(9.0).is_nan()); + $fassert!((<$fty>::NAN as $fty).maximum(-9.0).is_nan()); + $fassert!((9.0 as $fty).maximum(<$fty>::NAN).is_nan()); + $fassert!((-9.0 as $fty).maximum(<$fty>::NAN).is_nan()); + $fassert!((<$fty>::NAN as $fty).maximum(<$fty>::NAN).is_nan()); } #[test] fn midpoint() { @@ -863,38 +863,50 @@ macro_rules! test_float { $fassert!((0.0 as $fty).midpoint(0.0), 0.0); $fassert!((-0.0 as $fty).midpoint(-0.0), -0.0); $fassert!((-5.0 as $fty).midpoint(5.0), 0.0); - $fassert!(($max as $fty).midpoint($min), 0.0); - $fassert!(($min as $fty).midpoint($max), -0.0); - $fassert!(($max as $fty).midpoint($min_pos), $max / 2.); - $fassert!((-$max as $fty).midpoint($min_pos), -$max / 2.); - $fassert!(($max as $fty).midpoint(-$min_pos), $max / 2.); - $fassert!((-$max as $fty).midpoint(-$min_pos), -$max / 2.); - $fassert!(($min_pos as $fty).midpoint($max), $max / 2.); - $fassert!(($min_pos as $fty).midpoint(-$max), -$max / 2.); - $fassert!((-$min_pos as $fty).midpoint($max), $max / 2.); - $fassert!((-$min_pos as $fty).midpoint(-$max), -$max / 2.); - $fassert!(($max as $fty).midpoint($max), $max); - $fassert!(($min_pos as $fty).midpoint($min_pos), $min_pos); - $fassert!((-$min_pos as $fty).midpoint(-$min_pos), -$min_pos); - $fassert!(($max as $fty).midpoint(5.0), $max / 2.0 + 2.5); - $fassert!(($max as $fty).midpoint(-5.0), $max / 2.0 - 2.5); - $fassert!(($inf as $fty).midpoint($inf), $inf); - $fassert!(($neginf as $fty).midpoint($neginf), $neginf); - $fassert!(($nan as $fty).midpoint(1.0).is_nan()); - $fassert!((1.0 as $fty).midpoint($nan).is_nan()); - $fassert!(($nan as $fty).midpoint($nan).is_nan()); + $fassert!((<$fty>::MAX as $fty).midpoint(<$fty>::MIN), 0.0); + $fassert!((<$fty>::MIN as $fty).midpoint(<$fty>::MAX), -0.0); + $fassert!((<$fty>::MAX as $fty).midpoint(<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.); + $fassert!((-<$fty>::MAX as $fty).midpoint(<$fty>::MIN_POSITIVE), -<$fty>::MAX / 2.); + $fassert!((<$fty>::MAX as $fty).midpoint(-<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.); + $fassert!( + (-<$fty>::MAX as $fty).midpoint(-<$fty>::MIN_POSITIVE), + -<$fty>::MAX / 2. + ); + $fassert!((<$fty>::MIN_POSITIVE).midpoint(<$fty>::MAX), <$fty>::MAX / 2.); + $fassert!((<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MAX), -<$fty>::MAX / 2.); + $fassert!((-<$fty>::MIN_POSITIVE).midpoint(<$fty>::MAX), <$fty>::MAX / 2.); + $fassert!((-<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MAX), -<$fty>::MAX / 2.); + $fassert!((<$fty>::MAX as $fty).midpoint(<$fty>::MAX), <$fty>::MAX); + $fassert!( + (<$fty>::MIN_POSITIVE).midpoint(<$fty>::MIN_POSITIVE), + <$fty>::MIN_POSITIVE + ); + $fassert!( + (-<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MIN_POSITIVE), + -<$fty>::MIN_POSITIVE + ); + $fassert!((<$fty>::MAX as $fty).midpoint(5.0), <$fty>::MAX / 2.0 + 2.5); + $fassert!((<$fty>::MAX as $fty).midpoint(-5.0), <$fty>::MAX / 2.0 - 2.5); + $fassert!((<$fty>::INFINITY as $fty).midpoint(<$fty>::INFINITY), <$fty>::INFINITY); + $fassert!( + (<$fty>::NEG_INFINITY as $fty).midpoint(<$fty>::NEG_INFINITY), + <$fty>::NEG_INFINITY + ); + $fassert!((<$fty>::NAN as $fty).midpoint(1.0).is_nan()); + $fassert!((1.0 as $fty).midpoint(<$fty>::NAN).is_nan()); + $fassert!((<$fty>::NAN as $fty).midpoint(<$fty>::NAN).is_nan()); // test if large differences in magnitude are still correctly computed. // NOTE: that because of how small x and y are, x + y can never overflow // so (x + y) / 2.0 is always correct // in particular, `2.pow(i)` will never be at the max exponent, so it could // be safely doubled, while j is significantly smaller. - for i in $max_exp.saturating_sub(64)..$max_exp { + for i in <$fty>::MAX_EXP.saturating_sub(64)..<$fty>::MAX_EXP { for j in 0..64u8 { let large = <$fty>::from(2.0f32).powi(i); // a much smaller number, such that there is no chance of overflow to test // potential double rounding in midpoint's implementation. - let small = <$fty>::from(2.0f32).powi($max_exp - 1) + let small = (2.0 as $fty).powi(<$fty>::MAX_EXP - 1) * <$fty>::EPSILON * <$fty>::from(j); @@ -908,21 +920,21 @@ macro_rules! test_float { #[test] fn rem_euclid() { // FIXME: Use $fassert when rem_euclid becomes const - assert!($inf.rem_euclid((42.0 as $fty)).is_nan()); - assert_eq!((42.0 as $fty).rem_euclid($inf), (42.0 as $fty)); - assert!((42.0 as $fty).rem_euclid($nan).is_nan()); - assert!($inf.rem_euclid($inf).is_nan()); - assert!($inf.rem_euclid($nan).is_nan()); - assert!($nan.rem_euclid($inf).is_nan()); + assert!(<$fty>::INFINITY.rem_euclid((42.0 as $fty)).is_nan()); + assert_eq!((42.0 as $fty).rem_euclid(<$fty>::INFINITY), (42.0 as $fty)); + assert!((42.0 as $fty).rem_euclid(<$fty>::NAN).is_nan()); + assert!(<$fty>::INFINITY.rem_euclid(<$fty>::INFINITY).is_nan()); + assert!(<$fty>::INFINITY.rem_euclid(<$fty>::NAN).is_nan()); + assert!(<$fty>::NAN.rem_euclid(<$fty>::INFINITY).is_nan()); } #[test] fn div_euclid() { // FIXME: Use $fassert when div_euclid becomes const - assert_eq!((42.0 as $fty).div_euclid($inf), 0.0); - assert!((42.0 as $fty).div_euclid($nan).is_nan()); - assert!($inf.div_euclid($inf).is_nan()); - assert!($inf.div_euclid($nan).is_nan()); - assert!($nan.div_euclid($inf).is_nan()); + assert_eq!((42.0 as $fty).div_euclid(<$fty>::INFINITY), 0.0); + assert!((42.0 as $fty).div_euclid(<$fty>::NAN).is_nan()); + assert!(<$fty>::INFINITY.div_euclid(<$fty>::INFINITY).is_nan()); + assert!(<$fty>::INFINITY.div_euclid(<$fty>::NAN).is_nan()); + assert!(<$fty>::NAN.div_euclid(<$fty>::INFINITY).is_nan()); } } }; @@ -948,51 +960,7 @@ macro_rules! float_const_assert { }; } -test_float!( - f32, - float_assert, - f32, - f32::INFINITY, - f32::NEG_INFINITY, - f32::NAN, - f32::MIN, - f32::MAX, - f32::MIN_POSITIVE, - f32::MAX_EXP -); -test_float!( - f32_const, - float_const_assert, - f32, - f32::INFINITY, - f32::NEG_INFINITY, - f32::NAN, - f32::MIN, - f32::MAX, - f32::MIN_POSITIVE, - f32::MAX_EXP -); -test_float!( - f64, - float_assert, - f64, - f64::INFINITY, - f64::NEG_INFINITY, - f64::NAN, - f64::MIN, - f64::MAX, - f64::MIN_POSITIVE, - f64::MAX_EXP -); -test_float!( - f64_const, - float_const_assert, - f64, - f64::INFINITY, - f64::NEG_INFINITY, - f64::NAN, - f64::MIN, - f64::MAX, - f64::MIN_POSITIVE, - f64::MAX_EXP -); +test_float!(f32, float_assert, f32); +test_float!(f32_const, float_const_assert, f32); +test_float!(f64, float_assert, f64); +test_float!(f64_const, float_const_assert, f64); From e0ff77aea5c723934296b8a54d485dd11fbc4d6d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 May 2025 08:42:36 +0200 Subject: [PATCH 63/80] coretests: add abs() and copysign() tests, and remove now-unnecessary ui test --- library/coretests/tests/num/mod.rs | 101 +++++++++++--------- tests/ui/consts/const-eval/float_methods.rs | 46 --------- 2 files changed, 56 insertions(+), 91 deletions(-) delete mode 100644 tests/ui/consts/const-eval/float_methods.rs diff --git a/library/coretests/tests/num/mod.rs b/library/coretests/tests/num/mod.rs index cdde5b883aa9..1212d36a1b15 100644 --- a/library/coretests/tests/num/mod.rs +++ b/library/coretests/tests/num/mod.rs @@ -747,19 +747,19 @@ macro_rules! test_float { $fassert!((-0.0 as $fty).min(9.0), -0.0); $fassert!((-0.0 as $fty).min(9.0).is_sign_negative()); $fassert!((-0.0 as $fty).min(-9.0), -9.0); - $fassert!((<$fty>::INFINITY as $fty).min(9.0), 9.0); + $fassert!(<$fty>::INFINITY.min(9.0), 9.0); $fassert!((9.0 as $fty).min(<$fty>::INFINITY), 9.0); - $fassert!((<$fty>::INFINITY as $fty).min(-9.0), -9.0); + $fassert!(<$fty>::INFINITY.min(-9.0), -9.0); $fassert!((-9.0 as $fty).min(<$fty>::INFINITY), -9.0); - $fassert!((<$fty>::NEG_INFINITY as $fty).min(9.0), <$fty>::NEG_INFINITY); + $fassert!(<$fty>::NEG_INFINITY.min(9.0), <$fty>::NEG_INFINITY); $fassert!((9.0 as $fty).min(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!((<$fty>::NEG_INFINITY as $fty).min(-9.0), <$fty>::NEG_INFINITY); + $fassert!(<$fty>::NEG_INFINITY.min(-9.0), <$fty>::NEG_INFINITY); $fassert!((-9.0 as $fty).min(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!((<$fty>::NAN as $fty).min(9.0), 9.0); - $fassert!((<$fty>::NAN as $fty).min(-9.0), -9.0); + $fassert!(<$fty>::NAN.min(9.0), 9.0); + $fassert!(<$fty>::NAN.min(-9.0), -9.0); $fassert!((9.0 as $fty).min(<$fty>::NAN), 9.0); $fassert!((-9.0 as $fty).min(<$fty>::NAN), -9.0); - $fassert!((<$fty>::NAN as $fty).min(<$fty>::NAN).is_nan()); + $fassert!(<$fty>::NAN.min(<$fty>::NAN).is_nan()); } #[test] fn max() { @@ -777,19 +777,19 @@ macro_rules! test_float { $fassert!((0.0 as $fty).max(-9.0).is_sign_positive()); $fassert!((-0.0 as $fty).max(-9.0), -0.0); $fassert!((-0.0 as $fty).max(-9.0).is_sign_negative()); - $fassert!((<$fty>::INFINITY as $fty).max(9.0), <$fty>::INFINITY); + $fassert!(<$fty>::INFINITY.max(9.0), <$fty>::INFINITY); $fassert!((9.0 as $fty).max(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!((<$fty>::INFINITY as $fty).max(-9.0), <$fty>::INFINITY); + $fassert!(<$fty>::INFINITY.max(-9.0), <$fty>::INFINITY); $fassert!((-9.0 as $fty).max(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!((<$fty>::NEG_INFINITY as $fty).max(9.0), 9.0); + $fassert!(<$fty>::NEG_INFINITY.max(9.0), 9.0); $fassert!((9.0 as $fty).max(<$fty>::NEG_INFINITY), 9.0); - $fassert!((<$fty>::NEG_INFINITY as $fty).max(-9.0), -9.0); + $fassert!(<$fty>::NEG_INFINITY.max(-9.0), -9.0); $fassert!((-9.0 as $fty).max(<$fty>::NEG_INFINITY), -9.0); - $fassert!((<$fty>::NAN as $fty).max(9.0), 9.0); - $fassert!((<$fty>::NAN as $fty).max(-9.0), -9.0); + $fassert!(<$fty>::NAN.max(9.0), 9.0); + $fassert!(<$fty>::NAN.max(-9.0), -9.0); $fassert!((9.0 as $fty).max(<$fty>::NAN), 9.0); $fassert!((-9.0 as $fty).max(<$fty>::NAN), -9.0); - $fassert!((<$fty>::NAN as $fty).max(<$fty>::NAN).is_nan()); + $fassert!(<$fty>::NAN.max(<$fty>::NAN).is_nan()); } #[test] fn minimum() { @@ -806,19 +806,19 @@ macro_rules! test_float { $fassert!((-0.0 as $fty).minimum(9.0), -0.0); $fassert!((-0.0 as $fty).minimum(9.0).is_sign_negative()); $fassert!((-0.0 as $fty).minimum(-9.0), -9.0); - $fassert!((<$fty>::INFINITY as $fty).minimum(9.0), 9.0); + $fassert!(<$fty>::INFINITY.minimum(9.0), 9.0); $fassert!((9.0 as $fty).minimum(<$fty>::INFINITY), 9.0); - $fassert!((<$fty>::INFINITY as $fty).minimum(-9.0), -9.0); + $fassert!(<$fty>::INFINITY.minimum(-9.0), -9.0); $fassert!((-9.0 as $fty).minimum(<$fty>::INFINITY), -9.0); - $fassert!((<$fty>::NEG_INFINITY as $fty).minimum(9.0), <$fty>::NEG_INFINITY); + $fassert!(<$fty>::NEG_INFINITY.minimum(9.0), <$fty>::NEG_INFINITY); $fassert!((9.0 as $fty).minimum(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!((<$fty>::NEG_INFINITY as $fty).minimum(-9.0), <$fty>::NEG_INFINITY); + $fassert!(<$fty>::NEG_INFINITY.minimum(-9.0), <$fty>::NEG_INFINITY); $fassert!((-9.0 as $fty).minimum(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!((<$fty>::NAN as $fty).minimum(9.0).is_nan()); - $fassert!((<$fty>::NAN as $fty).minimum(-9.0).is_nan()); + $fassert!(<$fty>::NAN.minimum(9.0).is_nan()); + $fassert!(<$fty>::NAN.minimum(-9.0).is_nan()); $fassert!((9.0 as $fty).minimum(<$fty>::NAN).is_nan()); $fassert!((-9.0 as $fty).minimum(<$fty>::NAN).is_nan()); - $fassert!((<$fty>::NAN as $fty).minimum(<$fty>::NAN).is_nan()); + $fassert!(<$fty>::NAN.minimum(<$fty>::NAN).is_nan()); } #[test] fn maximum() { @@ -838,19 +838,19 @@ macro_rules! test_float { $fassert!((0.0 as $fty).maximum(-9.0).is_sign_positive()); $fassert!((-0.0 as $fty).maximum(-9.0), -0.0); $fassert!((-0.0 as $fty).maximum(-9.0).is_sign_negative()); - $fassert!((<$fty>::INFINITY as $fty).maximum(9.0), <$fty>::INFINITY); + $fassert!(<$fty>::INFINITY.maximum(9.0), <$fty>::INFINITY); $fassert!((9.0 as $fty).maximum(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!((<$fty>::INFINITY as $fty).maximum(-9.0), <$fty>::INFINITY); + $fassert!(<$fty>::INFINITY.maximum(-9.0), <$fty>::INFINITY); $fassert!((-9.0 as $fty).maximum(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!((<$fty>::NEG_INFINITY as $fty).maximum(9.0), 9.0); + $fassert!(<$fty>::NEG_INFINITY.maximum(9.0), 9.0); $fassert!((9.0 as $fty).maximum(<$fty>::NEG_INFINITY), 9.0); - $fassert!((<$fty>::NEG_INFINITY as $fty).maximum(-9.0), -9.0); + $fassert!(<$fty>::NEG_INFINITY.maximum(-9.0), -9.0); $fassert!((-9.0 as $fty).maximum(<$fty>::NEG_INFINITY), -9.0); - $fassert!((<$fty>::NAN as $fty).maximum(9.0).is_nan()); - $fassert!((<$fty>::NAN as $fty).maximum(-9.0).is_nan()); + $fassert!(<$fty>::NAN.maximum(9.0).is_nan()); + $fassert!(<$fty>::NAN.maximum(-9.0).is_nan()); $fassert!((9.0 as $fty).maximum(<$fty>::NAN).is_nan()); $fassert!((-9.0 as $fty).maximum(<$fty>::NAN).is_nan()); - $fassert!((<$fty>::NAN as $fty).maximum(<$fty>::NAN).is_nan()); + $fassert!(<$fty>::NAN.maximum(<$fty>::NAN).is_nan()); } #[test] fn midpoint() { @@ -863,20 +863,17 @@ macro_rules! test_float { $fassert!((0.0 as $fty).midpoint(0.0), 0.0); $fassert!((-0.0 as $fty).midpoint(-0.0), -0.0); $fassert!((-5.0 as $fty).midpoint(5.0), 0.0); - $fassert!((<$fty>::MAX as $fty).midpoint(<$fty>::MIN), 0.0); - $fassert!((<$fty>::MIN as $fty).midpoint(<$fty>::MAX), -0.0); - $fassert!((<$fty>::MAX as $fty).midpoint(<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.); - $fassert!((-<$fty>::MAX as $fty).midpoint(<$fty>::MIN_POSITIVE), -<$fty>::MAX / 2.); - $fassert!((<$fty>::MAX as $fty).midpoint(-<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.); - $fassert!( - (-<$fty>::MAX as $fty).midpoint(-<$fty>::MIN_POSITIVE), - -<$fty>::MAX / 2. - ); + $fassert!(<$fty>::MAX.midpoint(<$fty>::MIN), 0.0); + $fassert!(<$fty>::MIN.midpoint(<$fty>::MAX), -0.0); + $fassert!(<$fty>::MAX.midpoint(<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.); + $fassert!((-<$fty>::MAX).midpoint(<$fty>::MIN_POSITIVE), -<$fty>::MAX / 2.); + $fassert!(<$fty>::MAX.midpoint(-<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.); + $fassert!((-<$fty>::MAX).midpoint(-<$fty>::MIN_POSITIVE), -<$fty>::MAX / 2.); $fassert!((<$fty>::MIN_POSITIVE).midpoint(<$fty>::MAX), <$fty>::MAX / 2.); $fassert!((<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MAX), -<$fty>::MAX / 2.); $fassert!((-<$fty>::MIN_POSITIVE).midpoint(<$fty>::MAX), <$fty>::MAX / 2.); $fassert!((-<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MAX), -<$fty>::MAX / 2.); - $fassert!((<$fty>::MAX as $fty).midpoint(<$fty>::MAX), <$fty>::MAX); + $fassert!(<$fty>::MAX.midpoint(<$fty>::MAX), <$fty>::MAX); $fassert!( (<$fty>::MIN_POSITIVE).midpoint(<$fty>::MIN_POSITIVE), <$fty>::MIN_POSITIVE @@ -885,16 +882,16 @@ macro_rules! test_float { (-<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MIN_POSITIVE), -<$fty>::MIN_POSITIVE ); - $fassert!((<$fty>::MAX as $fty).midpoint(5.0), <$fty>::MAX / 2.0 + 2.5); - $fassert!((<$fty>::MAX as $fty).midpoint(-5.0), <$fty>::MAX / 2.0 - 2.5); - $fassert!((<$fty>::INFINITY as $fty).midpoint(<$fty>::INFINITY), <$fty>::INFINITY); + $fassert!(<$fty>::MAX.midpoint(5.0), <$fty>::MAX / 2.0 + 2.5); + $fassert!(<$fty>::MAX.midpoint(-5.0), <$fty>::MAX / 2.0 - 2.5); + $fassert!(<$fty>::INFINITY.midpoint(<$fty>::INFINITY), <$fty>::INFINITY); $fassert!( - (<$fty>::NEG_INFINITY as $fty).midpoint(<$fty>::NEG_INFINITY), + <$fty>::NEG_INFINITY.midpoint(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY ); - $fassert!((<$fty>::NAN as $fty).midpoint(1.0).is_nan()); + $fassert!(<$fty>::NAN.midpoint(1.0).is_nan()); $fassert!((1.0 as $fty).midpoint(<$fty>::NAN).is_nan()); - $fassert!((<$fty>::NAN as $fty).midpoint(<$fty>::NAN).is_nan()); + $fassert!(<$fty>::NAN.midpoint(<$fty>::NAN).is_nan()); // test if large differences in magnitude are still correctly computed. // NOTE: that because of how small x and y are, x + y can never overflow @@ -903,7 +900,7 @@ macro_rules! test_float { // be safely doubled, while j is significantly smaller. for i in <$fty>::MAX_EXP.saturating_sub(64)..<$fty>::MAX_EXP { for j in 0..64u8 { - let large = <$fty>::from(2.0f32).powi(i); + let large = (2.0 as $fty).powi(i); // a much smaller number, such that there is no chance of overflow to test // potential double rounding in midpoint's implementation. let small = (2.0 as $fty).powi(<$fty>::MAX_EXP - 1) @@ -918,6 +915,20 @@ macro_rules! test_float { } } #[test] + fn abs() { + $fassert!((-1.0 as $fty).abs(), 1.0); + $fassert!((1.0 as $fty).abs(), 1.0); + $fassert!(<$fty>::NEG_INFINITY.abs(), <$fty>::INFINITY); + $fassert!(<$fty>::INFINITY.abs(), <$fty>::INFINITY); + } + #[test] + fn copysign() { + $fassert!((1.0 as $fty).copysign(-2.0), -1.0); + $fassert!((-1.0 as $fty).copysign(2.0), 1.0); + $fassert!(<$fty>::INFINITY.copysign(-0.0), <$fty>::NEG_INFINITY); + $fassert!(<$fty>::NEG_INFINITY.copysign(0.0), <$fty>::INFINITY); + } + #[test] fn rem_euclid() { // FIXME: Use $fassert when rem_euclid becomes const assert!(<$fty>::INFINITY.rem_euclid((42.0 as $fty)).is_nan()); diff --git a/tests/ui/consts/const-eval/float_methods.rs b/tests/ui/consts/const-eval/float_methods.rs deleted file mode 100644 index 853f75825ac2..000000000000 --- a/tests/ui/consts/const-eval/float_methods.rs +++ /dev/null @@ -1,46 +0,0 @@ -//@ run-pass -//! Tests the float intrinsics: min, max, abs, copysign - -#![feature(f16, f128)] - -const F16_MIN: f16 = 1.0_f16.min(0.5_f16); -const F16_MAX: f16 = 1.0_f16.max(0.5_f16); -const F16_ABS: f16 = (-1.0_f16).abs(); -const F16_COPYSIGN: f16 = 1.0_f16.copysign(-2.0_f16); - -const F32_MIN: f32 = 1.0_f32.min(0.5_f32); -const F32_MAX: f32 = 1.0_f32.max(0.5_f32); -const F32_ABS: f32 = (-1.0_f32).abs(); -const F32_COPYSIGN: f32 = 1.0_f32.copysign(-2.0_f32); - -const F64_MIN: f64 = 1.0_f64.min(0.5_f64); -const F64_MAX: f64 = 1.0_f64.max(0.5_f64); -const F64_ABS: f64 = (-1.0_f64).abs(); -const F64_COPYSIGN: f64 = 1.0_f64.copysign(-2.0_f64); - -const F128_MIN: f128 = 1.0_f128.min(0.5_f128); -const F128_MAX: f128 = 1.0_f128.max(0.5_f128); -const F128_ABS: f128 = (-1.0_f128).abs(); -const F128_COPYSIGN: f128 = 1.0_f128.copysign(-2.0_f128); - -fn main() { - assert_eq!(F16_MIN, 0.5); - assert_eq!(F16_MAX, 1.0); - assert_eq!(F16_ABS, 1.0); - assert_eq!(F16_COPYSIGN, -1.0); - - assert_eq!(F32_MIN, 0.5); - assert_eq!(F32_MAX, 1.0); - assert_eq!(F32_ABS, 1.0); - assert_eq!(F32_COPYSIGN, -1.0); - - assert_eq!(F64_MIN, 0.5); - assert_eq!(F64_MAX, 1.0); - assert_eq!(F64_ABS, 1.0); - assert_eq!(F64_COPYSIGN, -1.0); - - assert_eq!(F128_MIN, 0.5); - assert_eq!(F128_MAX, 1.0); - assert_eq!(F128_ABS, 1.0); - assert_eq!(F128_COPYSIGN, -1.0); -} From bf52d1a8037c15ea67c21d857cb9ae6e2829931b Mon Sep 17 00:00:00 2001 From: MarcoIeni <11428655+MarcoIeni@users.noreply.github.com> Date: Wed, 28 May 2025 10:23:38 +0200 Subject: [PATCH 64/80] ci: verify that codebuild jobs use ghcr.io --- src/ci/citool/src/jobs/tests.rs | 66 +++++++++++++++++++++++++++++++++ src/ci/citool/src/main.rs | 2 +- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/ci/citool/src/jobs/tests.rs b/src/ci/citool/src/jobs/tests.rs index a489656fa5dc..ed5444d4333d 100644 --- a/src/ci/citool/src/jobs/tests.rs +++ b/src/ci/citool/src/jobs/tests.rs @@ -1,4 +1,8 @@ +use std::path::Path; + +use super::Job; use crate::jobs::{JobDatabase, load_job_db}; +use crate::{DOCKER_DIRECTORY, JOBS_YML_PATH, utils}; #[test] fn lookup_job_pattern() { @@ -62,3 +66,65 @@ fn check_pattern(db: &JobDatabase, pattern: &str, expected: &[&str]) { assert_eq!(jobs, expected); } + +/// Validate that CodeBuild jobs use Docker images from ghcr.io registry. +/// This is needed because otherwise from CodeBuild we get rate limited by Docker Hub. +fn validate_codebuild_image(job: &Job) -> anyhow::Result<()> { + let is_job_on_codebuild = job.codebuild.unwrap_or(false); + if !is_job_on_codebuild { + // Jobs in GitHub Actions don't get rate limited by Docker Hub. + return Ok(()); + } + + let image_name = job.image(); + // we hardcode host-x86_64 here, because in codebuild we only run jobs for this architecture. + let dockerfile_path = + Path::new(DOCKER_DIRECTORY).join("host-x86_64").join(&image_name).join("Dockerfile"); + + if !dockerfile_path.exists() { + return Err(anyhow::anyhow!( + "Dockerfile not found for CodeBuild job '{}' at path: {}", + job.name, + dockerfile_path.display() + )); + } + + let dockerfile_content = utils::read_to_string(&dockerfile_path)?; + + // Check if all FROM statement uses ghcr.io registry + let has_ghcr_from = dockerfile_content + .lines() + .filter(|line| line.trim_start().to_lowercase().starts_with("from ")) + .all(|line| line.contains("ghcr.io")); + + if !has_ghcr_from { + return Err(anyhow::anyhow!( + "CodeBuild job '{}' must use ghcr.io registry in its Dockerfile FROM statement. \ + Dockerfile path: {dockerfile_path:?}", + job.name, + )); + } + + Ok(()) +} + +#[test] +fn validate_jobs() { + let db = { + let default_jobs_file = Path::new(JOBS_YML_PATH); + let db_str = utils::read_to_string(default_jobs_file).unwrap(); + load_job_db(&db_str).expect("Failed to load job database") + }; + + let all_jobs = + db.pr_jobs.iter().chain(db.try_jobs.iter()).chain(db.auto_jobs.iter()).collect::>(); + + let errors: Vec = + all_jobs.into_iter().filter_map(|job| validate_codebuild_image(job).err()).collect(); + + if !errors.is_empty() { + let error_messages = + errors.into_iter().map(|e| format!("- {e}")).collect::>().join("\n"); + panic!("Job validation failed:\n{error_messages}"); + } +} diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index 87ce09cfb233..bb73a5ef909f 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -27,7 +27,7 @@ use crate::test_dashboard::generate_test_dashboard; use crate::utils::{load_env_var, output_details}; const CI_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/.."); -const DOCKER_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../docker"); +pub const DOCKER_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../docker"); const JOBS_YML_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../github-actions/jobs.yml"); struct GitHubContext { From 457e84f4d8015af33a7d1fa4d3776a2dac67f3a8 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 28 May 2025 10:14:25 +0200 Subject: [PATCH 65/80] fix: Handle included files better in IDE layer This does not fully fix things, but it introduces a function that can be used to fix occurences. When using `to_def` functionality, the input node needs to come from the macro expanded include, not the real file that was included. This does unfortunately add more caller burden, but there is not really a way around it. --- .../rust-analyzer/crates/hir/src/semantics.rs | 37 ++++++++-- .../crates/hir/src/semantics/source_to_def.rs | 24 +++---- .../crates/ide/src/expand_macro.rs | 67 +++++++++++++++---- 3 files changed, 97 insertions(+), 31 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 0dac64d6f2c9..aea22545ed5d 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -769,6 +769,31 @@ impl<'db> SemanticsImpl<'db> { }) } + /// Descends the token into the include expansion, if its file is an included file. + pub fn descend_token_into_include_expansion( + &self, + tok: InRealFile, + ) -> InFile { + let Some(include) = + self.s2d_cache.borrow_mut().get_or_insert_include_for(self.db, tok.file_id) + else { + return tok.into(); + }; + let span = self.db.real_span_map(tok.file_id).span_for_range(tok.value.text_range()); + let Some(InMacroFile { file_id, value: mut mapped_tokens }) = self.with_ctx(|ctx| { + Some( + ctx.cache + .get_or_insert_expansion(ctx.db, include) + .map_range_down(span)? + .map(SmallVec::<[_; 2]>::from_iter), + ) + }) else { + return tok.into(); + }; + // We should only get one result at most + mapped_tokens.pop().map_or_else(|| tok.into(), |(tok, _)| InFile::new(file_id.into(), tok)) + } + /// Maps a node down by mapping its first and last token down. pub fn descend_node_into_attributes(&self, node: N) -> SmallVec<[N; 1]> { // This might not be the correct way to do this, but it works for now @@ -1528,11 +1553,9 @@ impl<'db> SemanticsImpl<'db> { } pub fn resolve_macro_call2(&self, macro_call: InFile<&ast::MacroCall>) -> Option { - self.with_ctx(|ctx| { - ctx.macro_call_to_macro_call(macro_call) - .and_then(|call| macro_call_to_macro_id(ctx, call)) - .map(Into::into) - }) + self.to_def2(macro_call) + .and_then(|call| self.with_ctx(|ctx| macro_call_to_macro_id(ctx, call))) + .map(Into::into) } pub fn is_proc_macro_call(&self, macro_call: InFile<&ast::MacroCall>) -> bool { @@ -1647,6 +1670,10 @@ impl<'db> SemanticsImpl<'db> { T::to_def(self, src) } + pub fn to_def2(&self, src: InFile<&T>) -> Option { + T::to_def(self, src) + } + fn file_to_module_defs(&self, file: FileId) -> impl Iterator { self.with_ctx(|ctx| ctx.file_to_def(file).to_owned()).into_iter().map(Module::from) } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs index 172af456d921..7f6c9af47400 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs @@ -399,19 +399,6 @@ impl SourceToDefCtx<'_, '_> { Some((container, label?)) } - pub(super) fn item_to_macro_call(&mut self, src: InFile<&ast::Item>) -> Option { - let map = self.dyn_map(src)?; - map[keys::ATTR_MACRO_CALL].get(&AstPtr::new(src.value)).copied() - } - - pub(super) fn macro_call_to_macro_call( - &mut self, - src: InFile<&ast::MacroCall>, - ) -> Option { - let map = self.dyn_map(src)?; - map[keys::MACRO_CALL].get(&AstPtr::new(src.value)).copied() - } - /// (AttrId, derive attribute call id, derive call ids) pub(super) fn attr_to_derive_macro_call( &mut self, @@ -449,6 +436,17 @@ impl SourceToDefCtx<'_, '_> { .or_insert_with(|| container.child_by_source(db, file_id)) } + pub(super) fn item_to_macro_call(&mut self, src: InFile<&ast::Item>) -> Option { + self.to_def(src, keys::ATTR_MACRO_CALL) + } + + pub(super) fn macro_call_to_macro_call( + &mut self, + src: InFile<&ast::MacroCall>, + ) -> Option { + self.to_def(src, keys::MACRO_CALL) + } + pub(super) fn type_param_to_def( &mut self, src: InFile<&ast::TypeParam>, diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs index f8f9378b9e91..7c396339c145 100644 --- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs +++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs @@ -1,10 +1,10 @@ use hir::db::ExpandDatabase; -use hir::{ExpandResult, InFile, Semantics}; +use hir::{ExpandResult, InFile, InRealFile, Semantics}; use ide_db::{ FileId, RootDatabase, base_db::Crate, helpers::pick_best_token, syntax_helpers::prettify_macro_expansion, }; -use span::{Edition, SpanMap, SyntaxContext, TextRange, TextSize}; +use span::{SpanMap, SyntaxContext, TextRange, TextSize}; use stdx::format_to; use syntax::{AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T, ast, ted}; @@ -26,8 +26,9 @@ pub struct ExpandedMacro { // ![Expand Macro Recursively](https://user-images.githubusercontent.com/48062697/113020648-b3973180-917a-11eb-84a9-ecb921293dc5.gif) pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option { let sema = Semantics::new(db); - let file = sema.parse_guess_edition(position.file_id); - let krate = sema.file_to_module_def(position.file_id)?.krate().into(); + let file_id = sema.attach_first_edition(position.file_id)?; + let file = sema.parse(file_id); + let krate = sema.file_to_module_def(file_id.file_id(db))?.krate().into(); let tok = pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind { SyntaxKind::IDENT => 1, @@ -86,7 +87,10 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< return derive; } - let mut anc = tok.parent_ancestors(); + let mut anc = sema + .descend_token_into_include_expansion(InRealFile::new(file_id, tok)) + .value + .parent_ancestors(); let mut span_map = SpanMap::empty(); let mut error = String::new(); let (name, expanded, kind) = loop { @@ -95,14 +99,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< if let Some(item) = ast::Item::cast(node.clone()) { if let Some(def) = sema.resolve_attr_macro_call(&item) { break ( - def.name(db) - .display( - db, - sema.attach_first_edition(position.file_id) - .map(|it| it.edition(db)) - .unwrap_or(Edition::CURRENT), - ) - .to_string(), + def.name(db).display(db, file_id.edition(db)).to_string(), expand_macro_recur(&sema, &item, &mut error, &mut span_map, TextSize::new(0))?, SyntaxKind::MACRO_ITEMS, ); @@ -759,4 +756,48 @@ fn test() { "<>hi""#]], ); } + + #[test] + fn in_included() { + check( + r#" +//- minicore: include +//- /main.rs crate:main +include!("./included.rs"); +//- /included.rs +macro_rules! foo { + () => { fn item() {} }; +} +foo$0!(); +"#, + expect![[r#" + foo! + fn item(){}"#]], + ); + } + + #[test] + fn include() { + check( + r#" +//- minicore: include +//- /main.rs crate:main +include$0!("./included.rs"); +//- /included.rs +macro_rules! foo { + () => { fn item() {} }; +} +foo(); +"#, + expect![[r#" + include! + macro_rules! foo { + () => { + fn item(){} + + }; + } + foo();"#]], + ); + } } From 8231d888cfc8d4b8b2e47c0489d17d7f0bbbb169 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 28 May 2025 11:12:28 +0200 Subject: [PATCH 66/80] feat: Desugar assist for `let pat = expr?;` -> `let else` --- .../src/handlers/desugar_try_expr.rs | 281 ++++++++++++++++++ .../handlers/replace_try_expr_with_match.rs | 148 --------- .../crates/ide-assists/src/lib.rs | 4 +- .../crates/ide-assists/src/tests/generated.rs | 62 ++-- .../src/ast/syntax_factory/constructors.rs | 12 + 5 files changed, 336 insertions(+), 171 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs delete mode 100644 src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs new file mode 100644 index 000000000000..efadde9e3648 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs @@ -0,0 +1,281 @@ +use std::iter; + +use ide_db::{ + assists::{AssistId, ExprFillDefaultMode}, + ty_filter::TryEnum, +}; +use syntax::{ + AstNode, T, + ast::{ + self, + edit::{AstNodeEdit, IndentLevel}, + make, + syntax_factory::SyntaxFactory, + }, +}; + +use crate::assist_context::{AssistContext, Assists}; + +// Assist: desugar_try_expr_match +// +// Replaces a `try` expression with a `match` expression. +// +// ``` +// # //- minicore: try, option +// fn handle() { +// let pat = Some(true)$0?; +// } +// ``` +// -> +// ``` +// fn handle() { +// let pat = match Some(true) { +// Some(it) => it, +// None => return None, +// }; +// } +// ``` + +// Assist: desugar_try_expr_let_else +// +// Replaces a `try` expression with a `let else` statement. +// +// ``` +// # //- minicore: try, option +// fn handle() { +// let pat = Some(true)$0?; +// } +// ``` +// -> +// ``` +// fn handle() { +// let Some(pat) = Some(true) else { +// return None; +// }; +// } +// ``` +pub(crate) fn desugar_try_expr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let question_tok = ctx.find_token_syntax_at_offset(T![?])?; + let try_expr = question_tok.parent().and_then(ast::TryExpr::cast)?; + + let expr = try_expr.expr()?; + let expr_type_info = ctx.sema.type_of_expr(&expr)?; + + let try_enum = TryEnum::from_ty(&ctx.sema, &expr_type_info.original)?; + + let target = try_expr.syntax().text_range(); + acc.add( + AssistId::refactor_rewrite("desugar_try_expr_match"), + "Replace try expression with match", + target, + |edit| { + let sad_pat = match try_enum { + TryEnum::Option => make::path_pat(make::ext::ident_path("None")), + TryEnum::Result => make::tuple_struct_pat( + make::ext::ident_path("Err"), + iter::once(make::path_pat(make::ext::ident_path("err"))), + ) + .into(), + }; + let sad_expr = match try_enum { + TryEnum::Option => { + make::expr_return(Some(make::expr_path(make::ext::ident_path("None")))) + } + TryEnum::Result => make::expr_return(Some( + make::expr_call( + make::expr_path(make::ext::ident_path("Err")), + make::arg_list(iter::once(make::expr_path(make::ext::ident_path("err")))), + ) + .into(), + )), + }; + + let happy_arm = make::match_arm( + try_enum.happy_pattern(make::ident_pat(false, false, make::name("it")).into()), + None, + make::expr_path(make::ext::ident_path("it")), + ); + let sad_arm = make::match_arm(sad_pat, None, sad_expr); + + let match_arm_list = make::match_arm_list([happy_arm, sad_arm]); + + let expr_match = make::expr_match(expr.clone(), match_arm_list) + .indent(IndentLevel::from_node(try_expr.syntax())); + + edit.replace_ast::(try_expr.clone().into(), expr_match.into()); + }, + ); + + if let Some(let_stmt) = try_expr.syntax().parent().and_then(ast::LetStmt::cast) { + if let_stmt.let_else().is_none() { + let pat = let_stmt.pat()?; + acc.add( + AssistId::refactor_rewrite("desugar_try_expr_let_else"), + "Replace try expression with let else", + target, + |builder| { + let make = SyntaxFactory::with_mappings(); + let mut editor = builder.make_editor(let_stmt.syntax()); + + let indent_level = IndentLevel::from_node(let_stmt.syntax()); + let new_let_stmt = make.let_else_stmt( + try_enum.happy_pattern(pat), + let_stmt.ty(), + expr, + make.block_expr( + iter::once( + make.expr_stmt( + make.expr_return(Some(match try_enum { + TryEnum::Option => make.expr_path(make.ident_path("None")), + TryEnum::Result => make + .expr_call( + make.expr_path(make.ident_path("Err")), + make.arg_list(iter::once( + match ctx.config.expr_fill_default { + ExprFillDefaultMode::Todo => make + .expr_macro( + make.ident_path("todo"), + make.token_tree( + syntax::SyntaxKind::L_PAREN, + [], + ), + ) + .into(), + ExprFillDefaultMode::Underscore => { + make.expr_underscore().into() + } + ExprFillDefaultMode::Default => make + .expr_macro( + make.ident_path("todo"), + make.token_tree( + syntax::SyntaxKind::L_PAREN, + [], + ), + ) + .into(), + }, + )), + ) + .into(), + })) + .indent(indent_level + 1) + .into(), + ) + .into(), + ), + None, + ) + .indent(indent_level), + ); + editor.replace(let_stmt.syntax(), new_let_stmt.syntax()); + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.vfs_file_id(), editor); + }, + ); + } + } + Some(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + use crate::tests::{check_assist, check_assist_by_label, check_assist_not_applicable}; + + #[test] + fn test_desugar_try_expr_not_applicable() { + check_assist_not_applicable( + desugar_try_expr, + r#" + fn test() { + let pat: u32 = 25$0; + } + "#, + ); + } + + #[test] + fn test_desugar_try_expr_option() { + check_assist( + desugar_try_expr, + r#" +//- minicore: try, option +fn test() { + let pat = Some(true)$0?; +} + "#, + r#" +fn test() { + let pat = match Some(true) { + Some(it) => it, + None => return None, + }; +} + "#, + ); + } + + #[test] + fn test_desugar_try_expr_result() { + check_assist( + desugar_try_expr, + r#" +//- minicore: try, from, result +fn test() { + let pat = Ok(true)$0?; +} + "#, + r#" +fn test() { + let pat = match Ok(true) { + Ok(it) => it, + Err(err) => return Err(err), + }; +} + "#, + ); + } + + #[test] + fn test_desugar_try_expr_option_let_else() { + check_assist_by_label( + desugar_try_expr, + r#" +//- minicore: try, option +fn test() { + let pat = Some(true)$0?; +} + "#, + r#" +fn test() { + let Some(pat) = Some(true) else { + return None; + }; +} + "#, + "Replace try expression with let else", + ); + } + + #[test] + fn test_desugar_try_expr_result_let_else() { + check_assist_by_label( + desugar_try_expr, + r#" +//- minicore: try, from, result +fn test() { + let pat = Ok(true)$0?; +} + "#, + r#" +fn test() { + let Ok(pat) = Ok(true) else { + return Err(todo!()); + }; +} + "#, + "Replace try expression with let else", + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs deleted file mode 100644 index c6e864fcfdba..000000000000 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs +++ /dev/null @@ -1,148 +0,0 @@ -use std::iter; - -use ide_db::{assists::AssistId, ty_filter::TryEnum}; -use syntax::{ - AstNode, T, - ast::{ - self, - edit::{AstNodeEdit, IndentLevel}, - make, - }, -}; - -use crate::assist_context::{AssistContext, Assists}; - -// Assist: replace_try_expr_with_match -// -// Replaces a `try` expression with a `match` expression. -// -// ``` -// # //- minicore: try, option -// fn handle() { -// let pat = Some(true)$0?; -// } -// ``` -// -> -// ``` -// fn handle() { -// let pat = match Some(true) { -// Some(it) => it, -// None => return None, -// }; -// } -// ``` -pub(crate) fn replace_try_expr_with_match( - acc: &mut Assists, - ctx: &AssistContext<'_>, -) -> Option<()> { - let qm_kw = ctx.find_token_syntax_at_offset(T![?])?; - let qm_kw_parent = qm_kw.parent().and_then(ast::TryExpr::cast)?; - - let expr = qm_kw_parent.expr()?; - let expr_type_info = ctx.sema.type_of_expr(&expr)?; - - let try_enum = TryEnum::from_ty(&ctx.sema, &expr_type_info.original)?; - - let target = qm_kw_parent.syntax().text_range(); - acc.add( - AssistId::refactor_rewrite("replace_try_expr_with_match"), - "Replace try expression with match", - target, - |edit| { - let sad_pat = match try_enum { - TryEnum::Option => make::path_pat(make::ext::ident_path("None")), - TryEnum::Result => make::tuple_struct_pat( - make::ext::ident_path("Err"), - iter::once(make::path_pat(make::ext::ident_path("err"))), - ) - .into(), - }; - let sad_expr = match try_enum { - TryEnum::Option => { - make::expr_return(Some(make::expr_path(make::ext::ident_path("None")))) - } - TryEnum::Result => make::expr_return(Some( - make::expr_call( - make::expr_path(make::ext::ident_path("Err")), - make::arg_list(iter::once(make::expr_path(make::ext::ident_path("err")))), - ) - .into(), - )), - }; - - let happy_arm = make::match_arm( - try_enum.happy_pattern(make::ident_pat(false, false, make::name("it")).into()), - None, - make::expr_path(make::ext::ident_path("it")), - ); - let sad_arm = make::match_arm(sad_pat, None, sad_expr); - - let match_arm_list = make::match_arm_list([happy_arm, sad_arm]); - - let expr_match = make::expr_match(expr, match_arm_list) - .indent(IndentLevel::from_node(qm_kw_parent.syntax())); - edit.replace_ast::(qm_kw_parent.into(), expr_match.into()); - }, - ) -} - -#[cfg(test)] -mod tests { - use super::*; - - use crate::tests::{check_assist, check_assist_not_applicable}; - - #[test] - fn test_replace_try_expr_with_match_not_applicable() { - check_assist_not_applicable( - replace_try_expr_with_match, - r#" - fn test() { - let pat: u32 = 25$0; - } - "#, - ); - } - - #[test] - fn test_replace_try_expr_with_match_option() { - check_assist( - replace_try_expr_with_match, - r#" -//- minicore: try, option -fn test() { - let pat = Some(true)$0?; -} - "#, - r#" -fn test() { - let pat = match Some(true) { - Some(it) => it, - None => return None, - }; -} - "#, - ); - } - - #[test] - fn test_replace_try_expr_with_match_result() { - check_assist( - replace_try_expr_with_match, - r#" -//- minicore: try, from, result -fn test() { - let pat = Ok(true)$0?; -} - "#, - r#" -fn test() { - let pat = match Ok(true) { - Ok(it) => it, - Err(err) => return Err(err), - }; -} - "#, - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs index 2395091b6f2e..c2604432032d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -139,6 +139,7 @@ mod handlers { mod destructure_struct_binding; mod destructure_tuple_binding; mod desugar_doc_comment; + mod desugar_try_expr; mod expand_glob_import; mod expand_rest_pattern; mod extract_expressions_from_format_string; @@ -214,7 +215,6 @@ mod handlers { mod replace_named_generic_with_impl; mod replace_qualified_name_with_use; mod replace_string_with_char; - mod replace_try_expr_with_match; mod replace_turbofish_with_explicit_type; mod sort_items; mod split_import; @@ -273,6 +273,7 @@ mod handlers { destructure_struct_binding::destructure_struct_binding, destructure_tuple_binding::destructure_tuple_binding, desugar_doc_comment::desugar_doc_comment, + desugar_try_expr::desugar_try_expr, expand_glob_import::expand_glob_import, expand_glob_import::expand_glob_reexport, expand_rest_pattern::expand_rest_pattern, @@ -354,7 +355,6 @@ mod handlers { replace_method_eager_lazy::replace_with_lazy_method, replace_named_generic_with_impl::replace_named_generic_with_impl, replace_qualified_name_with_use::replace_qualified_name_with_use, - replace_try_expr_with_match::replace_try_expr_with_match, replace_turbofish_with_explicit_type::replace_turbofish_with_explicit_type, sort_items::sort_items, split_import::split_import, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 76134acb36eb..72f7195cbd77 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -929,6 +929,47 @@ comment"] ) } +#[test] +fn doctest_desugar_try_expr_let_else() { + check_doc_test( + "desugar_try_expr_let_else", + r#####" +//- minicore: try, option +fn handle() { + let pat = Some(true)$0?; +} +"#####, + r#####" +fn handle() { + let Some(pat) = Some(true) else { + return None; + }; +} +"#####, + ) +} + +#[test] +fn doctest_desugar_try_expr_match() { + check_doc_test( + "desugar_try_expr_match", + r#####" +//- minicore: try, option +fn handle() { + let pat = Some(true)$0?; +} +"#####, + r#####" +fn handle() { + let pat = match Some(true) { + Some(it) => it, + None => return None, + }; +} +"#####, + ) +} + #[test] fn doctest_expand_glob_import() { check_doc_test( @@ -3096,27 +3137,6 @@ fn main() { ) } -#[test] -fn doctest_replace_try_expr_with_match() { - check_doc_test( - "replace_try_expr_with_match", - r#####" -//- minicore: try, option -fn handle() { - let pat = Some(true)$0?; -} -"#####, - r#####" -fn handle() { - let pat = match Some(true) { - Some(it) => it, - None => return None, - }; -} -"#####, - ) -} - #[test] fn doctest_replace_turbofish_with_explicit_type() { check_doc_test( diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 8dee3964d448..429e51ba3621 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -585,6 +585,18 @@ impl SyntaxFactory { ast } + pub fn expr_underscore(&self) -> ast::UnderscoreExpr { + let ast::Expr::UnderscoreExpr(ast) = make::ext::expr_underscore().clone_for_update() else { + unreachable!() + }; + + if let Some(mut mapping) = self.mappings() { + SyntaxMappingBuilder::new(ast.syntax().clone()).finish(&mut mapping); + } + + ast + } + pub fn expr_if( &self, condition: ast::Expr, From 550aed825b3a630b5b2bd235e193bfce065268c2 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 26 May 2025 10:38:02 +0000 Subject: [PATCH 67/80] Use `builin_index` instead of hand-rolling it --- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 3 +-- compiler/rustc_hir_typeck/src/expr.rs | 10 ++-------- compiler/rustc_pattern_analysis/src/rustc.rs | 6 +++--- .../clippy/clippy_lints/src/index_refutable_slice.rs | 5 ++--- .../clippy/clippy_lints/src/tuple_array_conversions.rs | 4 ++-- src/tools/clippy/clippy_utils/src/consts.rs | 4 +--- 6 files changed, 11 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 06c5e518fc64..0f17cbc0ce80 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1048,8 +1048,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), match ty.kind() { ty::Adt(adt_def, ..) => adt_def.did().is_local(), // Arrays and slices use the inner type's `ConstParamTy`. - ty::Array(ty, ..) => ty_is_local(*ty), - ty::Slice(ty) => ty_is_local(*ty), + ty::Array(ty, ..) | ty::Slice(ty) => ty_is_local(*ty), // `&` references use the inner type's `ConstParamTy`. // `&mut` are not supported. ty::Ref(_, ty, ast::Mutability::Not) => ty_is_local(*ty), diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 1d86f7d223ce..082ddac7e5ae 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1793,10 +1793,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let element_ty = if !args.is_empty() { let coerce_to = expected .to_option(self) - .and_then(|uty| match *self.try_structurally_resolve_type(expr.span, uty).kind() { - ty::Array(ty, _) | ty::Slice(ty) => Some(ty), - _ => None, - }) + .and_then(|uty| self.try_structurally_resolve_type(expr.span, uty).builtin_index()) .unwrap_or_else(|| self.next_ty_var(expr.span)); let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args); assert_eq!(self.diverges.get(), Diverges::Maybe); @@ -1874,10 +1871,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let uty = match expected { - ExpectHasType(uty) => match *uty.kind() { - ty::Array(ty, _) | ty::Slice(ty) => Some(ty), - _ => None, - }, + ExpectHasType(uty) => uty.builtin_index(), _ => None, }; diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index d9f1888bfd9a..46ced7500ea2 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -249,12 +249,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ty::Ref(_, rty, _) => reveal_and_alloc(cx, once(*rty)), _ => bug!("Unexpected type for `Ref` constructor: {ty:?}"), }, - Slice(slice) => match *ty.kind() { - ty::Slice(ty) | ty::Array(ty, _) => { + Slice(slice) => match ty.builtin_index() { + Some(ty) => { let arity = slice.arity(); reveal_and_alloc(cx, (0..arity).map(|_| ty)) } - _ => bug!("bad slice pattern {:?} {:?}", ctor, ty), + None => bug!("bad slice pattern {:?} {:?}", ctor, ty), }, DerefPattern(pointee_ty) => reveal_and_alloc(cx, once(pointee_ty.inner())), Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs index 0b1cae30ca50..3d131a7825af 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -12,7 +12,6 @@ use rustc_hir::HirId; use rustc_hir::intravisit::{self, Visitor}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; -use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::Span; use rustc_span::symbol::Ident; @@ -109,11 +108,11 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap for TupleArrayConversions { } fn check_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &'tcx [Expr<'tcx>]) { - let (ty::Array(ty, _) | ty::Slice(ty)) = cx.typeck_results().expr_ty(expr).kind() else { + let Some(ty) = cx.typeck_results().expr_ty(expr).builtin_index() else { unreachable!("`expr` must be an array or slice due to `ExprKind::Array`"); }; @@ -85,7 +85,7 @@ fn check_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: & ExprKind::Path(_) => Some(elements.iter().collect()), _ => None, }) - && all_bindings_are_for_conv(cx, &[*ty], expr, elements, &locals, ToType::Array) + && all_bindings_are_for_conv(cx, &[ty], expr, elements, &locals, ToType::Array) && !is_from_proc_macro(cx, expr) { span_lint_and_help( diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 6f5b0ec54cd8..1ec5d11384f5 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -235,9 +235,7 @@ impl Constant<'_> { _ => None, }, (Self::Vec(l), Self::Vec(r)) => { - let (ty::Array(cmp_type, _) | ty::Slice(cmp_type)) = *cmp_type.kind() else { - return None; - }; + let cmp_type = cmp_type.builtin_index()?; iter::zip(l, r) .map(|(li, ri)| Self::partial_cmp(tcx, cmp_type, li, ri)) .find(|r| r.is_none_or(|o| o != Ordering::Equal)) From 0dd5722d6790be37b310c2e578be4f162d2be6ef Mon Sep 17 00:00:00 2001 From: Paul Mabileau Date: Fri, 16 May 2025 22:49:00 +0200 Subject: [PATCH 68/80] Test(fs): Fix test_eq_windows_file_type for Windows 7 Would otherwise fail on: ``` thread 'fs::tests::test_eq_windows_file_type' panicked at library/std/src/test_helpers.rs:53:20: called `Result::unwrap()` on an `Err` value: Os { code: 5, kind: PermissionDenied, message: "Access is denied." } ``` This came from the read-only attribute set on the test file. In order to fix this, instead of simply disabling the test, the attribute is reset before the test's end so it may still run successfully. Signed-off-by: Paul Mabileau --- library/std/src/fs/tests.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 8da6d75b73e1..c81e3af2f0d4 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1782,8 +1782,30 @@ fn test_eq_windows_file_type() { // Change the readonly attribute of one file. let mut perms = file1.metadata().unwrap().permissions(); perms.set_readonly(true); - file1.set_permissions(perms).unwrap(); + file1.set_permissions(perms.clone()).unwrap(); + #[cfg(target_vendor = "win7")] + let _g = ReadonlyGuard { file: &file1, perms }; assert_eq!(file1.metadata().unwrap().file_type(), file2.metadata().unwrap().file_type()); + + // Reset the attribute before the `TmpDir`'s drop that removes the + // associated directory, which fails with a `PermissionDenied` error when + // running under Windows 7. + #[cfg(target_vendor = "win7")] + struct ReadonlyGuard<'f> { + file: &'f File, + perms: fs::Permissions, + } + #[cfg(target_vendor = "win7")] + impl<'f> Drop for ReadonlyGuard<'f> { + fn drop(&mut self) { + self.perms.set_readonly(false); + let res = self.file.set_permissions(self.perms.clone()); + + if !thread::panicking() { + res.unwrap(); + } + } + } } /// Regression test for https://github.com/rust-lang/rust/issues/50619. From 9389daab8d37298587305127f587e4fdd0f20598 Mon Sep 17 00:00:00 2001 From: David Klank <155117116+davidjsonn@users.noreply.github.com> Date: Wed, 28 May 2025 13:50:38 +0300 Subject: [PATCH 69/80] replace TraitRef link memory.md --- src/doc/rustc-dev-guide/src/memory.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/memory.md b/src/doc/rustc-dev-guide/src/memory.md index eeb4a813980a..f766a51898e4 100644 --- a/src/doc/rustc-dev-guide/src/memory.md +++ b/src/doc/rustc-dev-guide/src/memory.md @@ -63,7 +63,7 @@ represented as a slice `&'tcx [tcx.types.i32, tcx.types.u32]`). [`mk_args`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.mk_args [adtdefid]: ./ty_module/generic_arguments.md#adtdef-and-defid [`Predicate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Predicate.html -[`TraitRef`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TraitRef.html +[`TraitRef`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.TraitRef.html [`ty::TyKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/sty/type.TyKind.html [traits]: ./traits/resolution.md From bcebf58accb50f2252a1bf728a8da2316a1c1e48 Mon Sep 17 00:00:00 2001 From: Nia Espera Date: Wed, 28 May 2025 13:04:37 +0200 Subject: [PATCH 70/80] interpret/allocation: make alloc fn be FnOnce --- compiler/rustc_middle/src/mir/interpret/allocation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index f17747558fc5..dd55d039794f 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -512,7 +512,7 @@ impl Allocation { pub fn adjust_from_tcx<'tcx, Prov: Provenance, Bytes: AllocBytes>( &self, cx: &impl HasDataLayout, - mut alloc_bytes: impl FnMut(&[u8], Align) -> InterpResult<'tcx, Bytes>, + alloc_bytes: impl FnOnce(&[u8], Align) -> InterpResult<'tcx, Bytes>, mut adjust_ptr: impl FnMut(Pointer) -> InterpResult<'tcx, Pointer>, ) -> InterpResult<'tcx, Allocation> { // Copy the data. From 3a736e2726dcd4cb534eaf64b25196fa45a26a03 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 28 May 2025 12:17:18 +0000 Subject: [PATCH 71/80] Handle e2021 precise capturing of unsafe binder --- compiler/rustc_middle/src/ty/closure.rs | 4 ++++ compiler/rustc_mir_build/src/builder/expr/as_place.rs | 4 ++-- tests/ui/unsafe-binders/cat-projection.rs | 3 +++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index ff9096695d4d..df67bb505a68 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -117,6 +117,10 @@ impl<'tcx> CapturedPlace<'tcx> { } }, + HirProjectionKind::UnwrapUnsafeBinder => { + write!(&mut symbol, "__unwrap").unwrap(); + } + // Ignore derefs for now, as they are likely caused by // autoderefs that don't appear in the original code. HirProjectionKind::Deref => {} diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index 830a129c5854..f8c64d7d13ed 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -101,12 +101,12 @@ fn convert_to_hir_projections_and_truncate_for_capture( variant = Some(*idx); continue; } + ProjectionElem::UnwrapUnsafeBinder(_) => HirProjectionKind::UnwrapUnsafeBinder, // These do not affect anything, they just make sure we know the right type. ProjectionElem::OpaqueCast(_) | ProjectionElem::Subtype(..) => continue, ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::UnwrapUnsafeBinder(_) => { + | ProjectionElem::Subslice { .. } => { // We don't capture array-access projections. // We can stop here as arrays are captured completely. break; diff --git a/tests/ui/unsafe-binders/cat-projection.rs b/tests/ui/unsafe-binders/cat-projection.rs index dd7a78d59b36..0ce8579a6882 100644 --- a/tests/ui/unsafe-binders/cat-projection.rs +++ b/tests/ui/unsafe-binders/cat-projection.rs @@ -1,3 +1,6 @@ +//@ revisions: e2015 e2021 +//@[e2015] edition: 2015 +//@[e2021] edition: 2021 //@ check-pass #![feature(unsafe_binders)] From d88641f8bc4c9ad1e0f528f0834c14da302be447 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 28 May 2025 15:36:32 +0300 Subject: [PATCH 72/80] rustbook: Bump versions of `onig` and `onig_sys` This fixes the build on GCC 15 --- src/tools/rustbook/Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 07c5106331bf..8893846b5fa5 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -1026,11 +1026,11 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "onig" -version = "6.4.0" +version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" +checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.0", "libc", "once_cell", "onig_sys", @@ -1038,9 +1038,9 @@ dependencies = [ [[package]] name = "onig_sys" -version = "69.8.1" +version = "69.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7" +checksum = "c7f86c6eef3d6df15f23bcfb6af487cbd2fed4e5581d58d5bf1f5f8b7f6727dc" dependencies = [ "cc", "pkg-config", From 2e99a880e22f5a1f3800e1a26828b188204d037e Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 28 May 2025 15:12:56 +0200 Subject: [PATCH 73/80] Add diagnostic items to sys::Mutex --- compiler/rustc_span/src/symbol.rs | 3 +++ library/std/src/sys/sync/mutex/futex.rs | 3 +++ library/std/src/sys/sync/mutex/pthread.rs | 3 +++ 3 files changed, 9 insertions(+) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 0447713fb05d..58091bc32d22 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2071,6 +2071,9 @@ symbols! { sym, sync, synthetic, + sys_mutex_lock, + sys_mutex_try_lock, + sys_mutex_unlock, t32, target, target_abi, diff --git a/library/std/src/sys/sync/mutex/futex.rs b/library/std/src/sys/sync/mutex/futex.rs index ce9b2daa5f80..01e91a6294a4 100644 --- a/library/std/src/sys/sync/mutex/futex.rs +++ b/library/std/src/sys/sync/mutex/futex.rs @@ -19,11 +19,13 @@ impl Mutex { } #[inline] + #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_try_lock")] pub fn try_lock(&self) -> bool { self.futex.compare_exchange(UNLOCKED, LOCKED, Acquire, Relaxed).is_ok() } #[inline] + #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_lock")] pub fn lock(&self) { if self.futex.compare_exchange(UNLOCKED, LOCKED, Acquire, Relaxed).is_err() { self.lock_contended(); @@ -80,6 +82,7 @@ impl Mutex { } #[inline] + #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_unlock")] pub unsafe fn unlock(&self) { if self.futex.swap(UNLOCKED, Release) == CONTENDED { // We only wake up one thread. When that thread locks the mutex, it diff --git a/library/std/src/sys/sync/mutex/pthread.rs b/library/std/src/sys/sync/mutex/pthread.rs index 75b4b9c6dad9..52588a7899a7 100644 --- a/library/std/src/sys/sync/mutex/pthread.rs +++ b/library/std/src/sys/sync/mutex/pthread.rs @@ -28,6 +28,7 @@ impl Mutex { } #[inline] + #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_lock")] pub fn lock(&self) { // SAFETY: we call `init` above, therefore reentrant locking is safe. // In `drop` we ensure that the mutex is not destroyed while locked. @@ -35,6 +36,7 @@ impl Mutex { } #[inline] + #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_unlock")] pub unsafe fn unlock(&self) { // SAFETY: the mutex can only be locked if it is already initialized // and we observed this initialization since we observed the locking. @@ -42,6 +44,7 @@ impl Mutex { } #[inline] + #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_try_lock")] pub fn try_lock(&self) -> bool { // SAFETY: we call `init` above, therefore reentrant locking is safe. // In `drop` we ensure that the mutex is not destroyed while locked. From 149b5b2567535af761d16ed388b653740db7a457 Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 28 May 2025 15:13:38 +0200 Subject: [PATCH 74/80] Make pthread Mutex internals less public --- library/std/src/sys/sync/mutex/pthread.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/sync/mutex/pthread.rs b/library/std/src/sys/sync/mutex/pthread.rs index 52588a7899a7..1d442248374d 100644 --- a/library/std/src/sys/sync/mutex/pthread.rs +++ b/library/std/src/sys/sync/mutex/pthread.rs @@ -6,7 +6,7 @@ use crate::sys::pal::sync as pal; use crate::sys::sync::OnceBox; pub struct Mutex { - pub pal: OnceBox, + pub(in crate::sys::sync) pal: OnceBox, } impl Mutex { From 9f12748086823f58bc03ab5f4390e98a69991127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sun, 2 Feb 2025 11:26:20 +0100 Subject: [PATCH 75/80] GCI: Check where-clauses for well-formedness at the def site --- .../rustc_hir_analysis/src/check/wfcheck.rs | 41 +++++++++++++++---- .../def-site-predicates-wf.rs | 9 ++++ .../def-site-predicates-wf.stderr | 13 ++++++ 3 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 tests/ui/generic-const-items/def-site-predicates-wf.rs create mode 100644 tests/ui/generic-const-items/def-site-predicates-wf.stderr diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 06c5e518fc64..5070ab138c52 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -298,11 +298,9 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<() check_item_fn(tcx, def_id, ident, item.span, sig.decl) } hir::ItemKind::Static(_, ty, ..) => { - check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid) - } - hir::ItemKind::Const(_, ty, ..) => { - check_item_type(tcx, def_id, ty.span, UnsizedHandling::Forbid) + check_static_item(tcx, def_id, ty.span, UnsizedHandling::Forbid) } + hir::ItemKind::Const(_, ty, ..) => check_const_item(tcx, def_id, ty.span, item.span), hir::ItemKind::Struct(_, _, hir_generics) => { let res = check_type_defn(tcx, item, false); check_variances_for_type_defn(tcx, item, hir_generics); @@ -366,7 +364,7 @@ fn check_foreign_item<'tcx>( check_item_fn(tcx, def_id, item.ident, item.span, sig.decl) } hir::ForeignItemKind::Static(ty, ..) => { - check_item_type(tcx, def_id, ty.span, UnsizedHandling::AllowIfForeignTail) + check_static_item(tcx, def_id, ty.span, UnsizedHandling::AllowIfForeignTail) } hir::ForeignItemKind::Type => Ok(()), } @@ -1331,14 +1329,13 @@ enum UnsizedHandling { AllowIfForeignTail, } -fn check_item_type( +#[instrument(level = "debug", skip(tcx, ty_span, unsized_handling))] +fn check_static_item( tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, unsized_handling: UnsizedHandling, ) -> Result<(), ErrorGuaranteed> { - debug!("check_item_type: {:?}", item_id); - enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| { let ty = tcx.type_of(item_id).instantiate_identity(); let item_ty = wfcx.deeply_normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty); @@ -1388,6 +1385,34 @@ fn check_item_type( }) } +fn check_const_item( + tcx: TyCtxt<'_>, + def_id: LocalDefId, + ty_span: Span, + item_span: Span, +) -> Result<(), ErrorGuaranteed> { + enter_wf_checking_ctxt(tcx, ty_span, def_id, |wfcx| { + let ty = tcx.type_of(def_id).instantiate_identity(); + let ty = wfcx.deeply_normalize(ty_span, Some(WellFormedLoc::Ty(def_id)), ty); + + wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(def_id)), ty.into()); + wfcx.register_bound( + traits::ObligationCause::new( + ty_span, + wfcx.body_def_id, + ObligationCauseCode::SizedConstOrStatic, + ), + wfcx.param_env, + ty, + tcx.require_lang_item(LangItem::Sized, None), + ); + + check_where_clauses(wfcx, item_span, def_id); + + Ok(()) + }) +} + #[instrument(level = "debug", skip(tcx, hir_self_ty, hir_trait_ref))] fn check_impl<'tcx>( tcx: TyCtxt<'tcx>, diff --git a/tests/ui/generic-const-items/def-site-predicates-wf.rs b/tests/ui/generic-const-items/def-site-predicates-wf.rs new file mode 100644 index 000000000000..39cdcc304f3e --- /dev/null +++ b/tests/ui/generic-const-items/def-site-predicates-wf.rs @@ -0,0 +1,9 @@ +//! Ensure that we check the predicates for well-formedness at the definition site. +#![feature(generic_const_items)] +#![expect(incomplete_features)] + +const _: () = () +where + Vec: Sized; //~ ERROR the size for values of type `str` cannot be known at compilation time + +fn main() {} diff --git a/tests/ui/generic-const-items/def-site-predicates-wf.stderr b/tests/ui/generic-const-items/def-site-predicates-wf.stderr new file mode 100644 index 000000000000..62db089fd557 --- /dev/null +++ b/tests/ui/generic-const-items/def-site-predicates-wf.stderr @@ -0,0 +1,13 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/def-site-predicates-wf.rs:7:15 + | +LL | Vec: Sized; + | ^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` +note: required by an implicit `Sized` bound in `Vec` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. From 2593df8837f330301b5679e33efd54f36ba43c43 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 May 2025 15:06:08 +0200 Subject: [PATCH 76/80] core: unstably expose atomic_compare_exchange so stdarch can use it --- library/core/src/sync/atomic.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index bd5a58d74ba0..6bc6bee682df 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -3885,10 +3885,13 @@ unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { } } +/// Publicly exposed for stdarch; nobody else should use this. #[inline] #[cfg(target_has_atomic)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces -unsafe fn atomic_compare_exchange( +#[unstable(feature = "core_intrinsics", issue = "none")] +#[doc(hidden)] +pub unsafe fn atomic_compare_exchange( dst: *mut T, old: T, new: T, From 467eeabbb5e876abc6bf552670199695172ad07a Mon Sep 17 00:00:00 2001 From: beetrees Date: Sun, 9 Mar 2025 19:03:12 +0000 Subject: [PATCH 77/80] Stabilise `repr128` --- .../src/error_codes/E0658.md | 12 +- compiler/rustc_feature/src/accepted.rs | 2 + compiler/rustc_feature/src/unstable.rs | 2 - .../rustc_hir_analysis/src/check/check.rs | 15 +- .../src/language-features/repr128.md | 18 -- .../tests/ui/auxiliary/proc_macro_attr.rs | 3 +- .../tests/ui/auxiliary/proc_macro_derive.rs | 3 +- src/tools/clippy/tests/ui/cast.rs | 2 - src/tools/clippy/tests/ui/cast.stderr | 184 +++++++++--------- .../ui/crashes/auxiliary/proc_macro_crash.rs | 3 - src/tools/tidy/src/issues.txt | 1 - tests/codegen/enum/enum-u128.rs | 3 - tests/debuginfo/msvc-pretty-enums.rs | 2 - tests/mir-opt/enum_opt.rs | 2 - tests/mir-opt/matches_reduce_branches.rs | 1 - tests/run-make/repr128-dwarf/main.rs | 2 - .../rustdoc-json/enums/discriminant/limits.rs | 3 - .../ui/enum-discriminant/discriminant_size.rs | 3 +- .../discriminant_size.stderr | 11 -- tests/ui/enum-discriminant/issue-43398.stderr | 11 -- .../issue-70509-partial_eq.rs | 2 - .../issue-70509-partial_eq.stderr | 11 -- ...> repr128-get-discriminant-issue-43398.rs} | 2 - tests/ui/enum-discriminant/repr128.rs | 3 +- tests/ui/enum-discriminant/repr128.stderr | 11 -- tests/ui/error-codes/E0658.rs | 5 +- tests/ui/error-codes/E0658.stderr | 11 +- .../ui/feature-gates/feature-gate-repr128.rs | 6 - .../feature-gates/feature-gate-repr128.stderr | 13 -- tests/ui/lint/lint-ctypes-enum.rs | 2 - tests/ui/lint/lint-ctypes-enum.stderr | 68 +++---- .../enums/repr/should_handle_all.rs | 3 +- 32 files changed, 143 insertions(+), 277 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/repr128.md delete mode 100644 tests/ui/enum-discriminant/discriminant_size.stderr delete mode 100644 tests/ui/enum-discriminant/issue-43398.stderr delete mode 100644 tests/ui/enum-discriminant/issue-70509-partial_eq.stderr rename tests/ui/enum-discriminant/{issue-43398.rs => repr128-get-discriminant-issue-43398.rs} (75%) delete mode 100644 tests/ui/enum-discriminant/repr128.stderr delete mode 100644 tests/ui/feature-gates/feature-gate-repr128.rs delete mode 100644 tests/ui/feature-gates/feature-gate-repr128.stderr diff --git a/compiler/rustc_error_codes/src/error_codes/E0658.md b/compiler/rustc_error_codes/src/error_codes/E0658.md index 24245a38ae07..65c82e4fb6ef 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0658.md +++ b/compiler/rustc_error_codes/src/error_codes/E0658.md @@ -3,10 +3,7 @@ An unstable feature was used. Erroneous code example: ```compile_fail,E0658 -#[repr(u128)] // error: use of unstable library feature 'repr128' -enum Foo { - Bar(u64), -} +use std::intrinsics; // error: use of unstable library feature `core_intrinsics` ``` If you're using a stable or a beta version of rustc, you won't be able to use @@ -17,12 +14,9 @@ If you're using a nightly version of rustc, just add the corresponding feature to be able to use it: ``` -#![feature(repr128)] +#![feature(core_intrinsics)] -#[repr(u128)] // ok! -enum Foo { - Bar(u64), -} +use std::intrinsics; // ok! ``` [rustup]: https://rust-lang.github.io/rustup/concepts/channels.html diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 820af9ac84b2..ffa6ffb40b61 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -360,6 +360,8 @@ declare_features! ( (accepted, relaxed_adts, "1.19.0", Some(35626)), /// Lessens the requirements for structs to implement `Unsize`. (accepted, relaxed_struct_unsize, "1.58.0", Some(81793)), + /// Allows the `#[repr(i128)]` attribute for enums. + (accepted, repr128, "CURRENT_RUSTC_VERSION", Some(56071)), /// Allows `repr(align(16))` struct attribute (RFC 1358). (accepted, repr_align, "1.25.0", Some(33626)), /// Allows using `#[repr(align(X))]` on enums with equivalent semantics diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 3e408a031118..b46eac6d8a60 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -621,8 +621,6 @@ declare_features! ( (incomplete, ref_pat_eat_one_layer_2024_structural, "1.81.0", Some(123076)), /// Allows using the `#[register_tool]` attribute. (unstable, register_tool, "1.41.0", Some(66079)), - /// Allows the `#[repr(i128)]` attribute for enums. - (incomplete, repr128, "1.16.0", Some(56071)), /// Allows `repr(simd)` and importing the various simd intrinsics. (unstable, repr_simd, "1.4.0", Some(27731)), /// Allows bounding the return type of AFIT/RPITIT. diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index db7a5fe78976..846eacce9e10 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -18,7 +18,7 @@ use rustc_middle::middle::resolve_bound_vars::ResolvedArg; use rustc_middle::middle::stability::EvalResult; use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; -use rustc_middle::ty::util::{Discr, IntTypeExt}; +use rustc_middle::ty::util::Discr; use rustc_middle::ty::{ AdtDef, BottomUpFolder, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, fold_regions, @@ -1385,19 +1385,6 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { ); } - let repr_type_ty = def.repr().discr_type().to_ty(tcx); - if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 { - if !tcx.features().repr128() { - feature_err( - &tcx.sess, - sym::repr128, - tcx.def_span(def_id), - "repr with 128-bit type is unstable", - ) - .emit(); - } - } - for v in def.variants() { if let ty::VariantDiscr::Explicit(discr_def_id) = v.discr { tcx.ensure_ok().typeck(discr_def_id.expect_local()); diff --git a/src/doc/unstable-book/src/language-features/repr128.md b/src/doc/unstable-book/src/language-features/repr128.md deleted file mode 100644 index 146f50ee67b5..000000000000 --- a/src/doc/unstable-book/src/language-features/repr128.md +++ /dev/null @@ -1,18 +0,0 @@ -# `repr128` - -The tracking issue for this feature is: [#56071] - -[#56071]: https://github.com/rust-lang/rust/issues/56071 - ------------------------- - -The `repr128` feature adds support for `#[repr(u128)]` on `enum`s. - -```rust -#![feature(repr128)] - -#[repr(u128)] -enum Foo { - Bar(u64), -} -``` diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs index 4c61c5accd39..9b8e62867f0a 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs @@ -1,5 +1,4 @@ -#![feature(repr128, proc_macro_hygiene, proc_macro_quote, box_patterns)] -#![allow(incomplete_features)] +#![feature(proc_macro_hygiene, proc_macro_quote, box_patterns)] #![allow(clippy::useless_conversion, clippy::uninlined_format_args)] extern crate proc_macro; diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs index 1815dd58f510..5992d15935d5 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs @@ -1,5 +1,4 @@ -#![feature(repr128, proc_macro_quote, proc_macro_span)] -#![allow(incomplete_features)] +#![feature(proc_macro_quote, proc_macro_span)] #![allow(clippy::field_reassign_with_default)] #![allow(clippy::eq_op)] #![allow(clippy::literal_string_with_formatting_args)] diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs index 77329cf5455d..525be8216500 100644 --- a/src/tools/clippy/tests/ui/cast.rs +++ b/src/tools/clippy/tests/ui/cast.rs @@ -1,7 +1,5 @@ //@no-rustfix: only some diagnostics have suggestions -#![feature(repr128)] -#![allow(incomplete_features)] #![warn( clippy::cast_precision_loss, clippy::cast_possible_truncation, diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr index 4d03282f6676..1cb30d956679 100644 --- a/src/tools/clippy/tests/ui/cast.stderr +++ b/src/tools/clippy/tests/ui/cast.stderr @@ -1,5 +1,5 @@ error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:25:5 + --> tests/ui/cast.rs:23:5 | LL | x0 as f32; | ^^^^^^^^^ @@ -8,37 +8,37 @@ LL | x0 as f32; = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:29:5 + --> tests/ui/cast.rs:27:5 | LL | x1 as f32; | ^^^^^^^^^ error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:32:5 + --> tests/ui/cast.rs:30:5 | LL | x1 as f64; | ^^^^^^^^^ error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:36:5 + --> tests/ui/cast.rs:34:5 | LL | x2 as f32; | ^^^^^^^^^ error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast.rs:40:5 + --> tests/ui/cast.rs:38:5 | LL | x3 as f32; | ^^^^^^^^^ error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast.rs:43:5 + --> tests/ui/cast.rs:41:5 | LL | x3 as f64; | ^^^^^^^^^ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:47:5 + --> tests/ui/cast.rs:45:5 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | 1f32 as i32; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]` error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:50:5 + --> tests/ui/cast.rs:48:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | 1f32 as u32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:50:5 + --> tests/ui/cast.rs:48:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | 1f32 as u32; = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]` error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:54:5 + --> tests/ui/cast.rs:52:5 | LL | 1f64 as f32; | ^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | 1f64 as f32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:57:5 + --> tests/ui/cast.rs:55:5 | LL | 1i32 as i8; | ^^^^^^^^^^ @@ -86,7 +86,7 @@ LL + i8::try_from(1i32); | error: casting `i32` to `u8` may truncate the value - --> tests/ui/cast.rs:60:5 + --> tests/ui/cast.rs:58:5 | LL | 1i32 as u8; | ^^^^^^^^^^ @@ -99,7 +99,7 @@ LL + u8::try_from(1i32); | error: casting `f64` to `isize` may truncate the value - --> tests/ui/cast.rs:63:5 + --> tests/ui/cast.rs:61:5 | LL | 1f64 as isize; | ^^^^^^^^^^^^^ @@ -107,7 +107,7 @@ LL | 1f64 as isize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may truncate the value - --> tests/ui/cast.rs:66:5 + --> tests/ui/cast.rs:64:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ @@ -115,13 +115,13 @@ LL | 1f64 as usize; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:66:5 + --> tests/ui/cast.rs:64:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting `u32` to `u16` may truncate the value - --> tests/ui/cast.rs:70:5 + --> tests/ui/cast.rs:68:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^^^^^^^^ @@ -134,7 +134,7 @@ LL + u16::try_from(1f32 as u32); | error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:70:5 + --> tests/ui/cast.rs:68:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ @@ -142,13 +142,13 @@ LL | 1f32 as u32 as u16; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:70:5 + --> tests/ui/cast.rs:68:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:76:22 + --> tests/ui/cast.rs:74:22 | LL | let _x: i8 = 1i32 as _; | ^^^^^^^^^ @@ -161,7 +161,7 @@ LL + let _x: i8 = 1i32.try_into(); | error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:79:9 + --> tests/ui/cast.rs:77:9 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL | 1f32 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f64` to `i32` may truncate the value - --> tests/ui/cast.rs:82:9 + --> tests/ui/cast.rs:80:9 | LL | 1f64 as i32; | ^^^^^^^^^^^ @@ -177,7 +177,7 @@ LL | 1f64 as i32; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may truncate the value - --> tests/ui/cast.rs:85:9 + --> tests/ui/cast.rs:83:9 | LL | 1f32 as u8; | ^^^^^^^^^^ @@ -185,13 +185,13 @@ LL | 1f32 as u8; = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... error: casting `f32` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:85:9 + --> tests/ui/cast.rs:83:9 | LL | 1f32 as u8; | ^^^^^^^^^^ error: casting `u8` to `i8` may wrap around the value - --> tests/ui/cast.rs:90:5 + --> tests/ui/cast.rs:88:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -200,31 +200,31 @@ LL | 1u8 as i8; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` error: casting `u16` to `i16` may wrap around the value - --> tests/ui/cast.rs:93:5 + --> tests/ui/cast.rs:91:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting `u32` to `i32` may wrap around the value - --> tests/ui/cast.rs:96:5 + --> tests/ui/cast.rs:94:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting `u64` to `i64` may wrap around the value - --> tests/ui/cast.rs:99:5 + --> tests/ui/cast.rs:97:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting `usize` to `isize` may wrap around the value - --> tests/ui/cast.rs:102:5 + --> tests/ui/cast.rs:100:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting `usize` to `i8` may truncate the value - --> tests/ui/cast.rs:106:5 + --> tests/ui/cast.rs:104:5 | LL | 1usize as i8; | ^^^^^^^^^^^^ @@ -237,7 +237,7 @@ LL + i8::try_from(1usize); | error: casting `usize` to `i16` may truncate the value - --> tests/ui/cast.rs:110:5 + --> tests/ui/cast.rs:108:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -250,7 +250,7 @@ LL + i16::try_from(1usize); | error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:110:5 + --> tests/ui/cast.rs:108:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -259,7 +259,7 @@ LL | 1usize as i16; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:115:5 + --> tests/ui/cast.rs:113:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -272,19 +272,19 @@ LL + i32::try_from(1usize); | error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:115:5 + --> tests/ui/cast.rs:113:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:120:5 + --> tests/ui/cast.rs:118:5 | LL | 1usize as i64; | ^^^^^^^^^^^^^ error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers - --> tests/ui/cast.rs:126:5 + --> tests/ui/cast.rs:124:5 | LL | 1u16 as isize; | ^^^^^^^^^^^^^ @@ -293,13 +293,13 @@ LL | 1u16 as isize; = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:130:5 + --> tests/ui/cast.rs:128:5 | LL | 1u32 as isize; | ^^^^^^^^^^^^^ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:134:5 + --> tests/ui/cast.rs:132:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ @@ -312,55 +312,55 @@ LL + isize::try_from(1u64); | error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers - --> tests/ui/cast.rs:134:5 + --> tests/ui/cast.rs:132:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:140:5 + --> tests/ui/cast.rs:138:5 | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:144:5 + --> tests/ui/cast.rs:142:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i8` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:156:5 + --> tests/ui/cast.rs:154:5 | LL | (i8::MIN).abs() as u8; | ^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:161:5 + --> tests/ui/cast.rs:159:5 | LL | (-1i64).abs() as u64; | ^^^^^^^^^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:163:5 + --> tests/ui/cast.rs:161:5 | LL | (-1isize).abs() as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:171:5 + --> tests/ui/cast.rs:169:5 | LL | (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:187:5 + --> tests/ui/cast.rs:185:5 | LL | (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> tests/ui/cast.rs:239:5 + --> tests/ui/cast.rs:237:5 | LL | (-99999999999i64).min(1) as i8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -373,7 +373,7 @@ LL + i8::try_from((-99999999999i64).min(1)); | error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:253:5 + --> tests/ui/cast.rs:251:5 | LL | 999999u64.clamp(0, 256) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -386,7 +386,7 @@ LL + u8::try_from(999999u64.clamp(0, 256)); | error: casting `main::E2` to `u8` may truncate the value - --> tests/ui/cast.rs:276:21 + --> tests/ui/cast.rs:274:21 | LL | let _ = self as u8; | ^^^^^^^^^^ @@ -399,7 +399,7 @@ LL + let _ = u8::try_from(self); | error: casting `main::E2::B` to `u8` will truncate the value - --> tests/ui/cast.rs:279:21 + --> tests/ui/cast.rs:277:21 | LL | let _ = Self::B as u8; | ^^^^^^^^^^^^^ @@ -408,7 +408,7 @@ LL | let _ = Self::B as u8; = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]` error: casting `main::E5` to `i8` may truncate the value - --> tests/ui/cast.rs:321:21 + --> tests/ui/cast.rs:319:21 | LL | let _ = self as i8; | ^^^^^^^^^^ @@ -421,13 +421,13 @@ LL + let _ = i8::try_from(self); | error: casting `main::E5::A` to `i8` will truncate the value - --> tests/ui/cast.rs:324:21 + --> tests/ui/cast.rs:322:21 | LL | let _ = Self::A as i8; | ^^^^^^^^^^^^^ error: casting `main::E6` to `i16` may truncate the value - --> tests/ui/cast.rs:342:21 + --> tests/ui/cast.rs:340:21 | LL | let _ = self as i16; | ^^^^^^^^^^^ @@ -440,7 +440,7 @@ LL + let _ = i16::try_from(self); | error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:362:21 + --> tests/ui/cast.rs:360:21 | LL | let _ = self as usize; | ^^^^^^^^^^^^^ @@ -453,7 +453,7 @@ LL + let _ = usize::try_from(self); | error: casting `main::E10` to `u16` may truncate the value - --> tests/ui/cast.rs:410:21 + --> tests/ui/cast.rs:408:21 | LL | let _ = self as u16; | ^^^^^^^^^^^ @@ -466,7 +466,7 @@ LL + let _ = u16::try_from(self); | error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:422:13 + --> tests/ui/cast.rs:420:13 | LL | let c = (q >> 16) as u8; | ^^^^^^^^^^^^^^^ @@ -479,7 +479,7 @@ LL + let c = u8::try_from(q >> 16); | error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:427:13 + --> tests/ui/cast.rs:425:13 | LL | let c = (q / 1000) as u8; | ^^^^^^^^^^^^^^^^ @@ -492,85 +492,85 @@ LL + let c = u8::try_from(q / 1000); | error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:440:9 + --> tests/ui/cast.rs:438:9 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:446:32 + --> tests/ui/cast.rs:444:32 | LL | let _a = |x: i32| -> u32 { (x * x * x * x) as u32 }; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:449:5 + --> tests/ui/cast.rs:447:5 | LL | (2_i32).checked_pow(3).unwrap() as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:451:5 + --> tests/ui/cast.rs:449:5 | LL | (-2_i32).pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:456:5 + --> tests/ui/cast.rs:454:5 | LL | (-5_i32 % 2) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:459:5 + --> tests/ui/cast.rs:457:5 | LL | (-5_i32 % -2) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:463:5 + --> tests/ui/cast.rs:461:5 | LL | (-2_i32 >> 1) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:467:5 + --> tests/ui/cast.rs:465:5 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:469:5 + --> tests/ui/cast.rs:467:5 | LL | (x * x * x) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:473:5 + --> tests/ui/cast.rs:471:5 | LL | (y * y * y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:476:5 + --> tests/ui/cast.rs:474:5 | LL | (y * y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:478:5 + --> tests/ui/cast.rs:476:5 | LL | (y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:481:5 + --> tests/ui/cast.rs:479:5 | LL | (y / y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `/` - --> tests/ui/cast.rs:481:6 + --> tests/ui/cast.rs:479:6 | LL | (y / y * y * -2) as u16; | ^^^^^ @@ -578,97 +578,97 @@ LL | (y / y * y * -2) as u16; = note: `#[deny(clippy::eq_op)]` on by default error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:485:5 + --> tests/ui/cast.rs:483:5 | LL | (y + y + y + -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:488:5 + --> tests/ui/cast.rs:486:5 | LL | (y + y + y + 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:492:5 + --> tests/ui/cast.rs:490:5 | LL | (z + -2) as u16; | ^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:495:5 + --> tests/ui/cast.rs:493:5 | LL | (z + z + 2) as u16; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:499:9 + --> tests/ui/cast.rs:497:9 | LL | (a * a * b * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:501:9 + --> tests/ui/cast.rs:499:9 | LL | (a * b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:504:9 + --> tests/ui/cast.rs:502:9 | LL | (a * -b * c) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:507:9 + --> tests/ui/cast.rs:505:9 | LL | (a * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:509:9 + --> tests/ui/cast.rs:507:9 | LL | (a * -2) as u32; | ^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:512:9 + --> tests/ui/cast.rs:510:9 | LL | (a * b * c * -2) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:515:9 + --> tests/ui/cast.rs:513:9 | LL | (a / b) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:517:9 + --> tests/ui/cast.rs:515:9 | LL | (a / b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:520:9 + --> tests/ui/cast.rs:518:9 | LL | (a / b + b * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:523:9 + --> tests/ui/cast.rs:521:9 | LL | a.saturating_pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:526:9 + --> tests/ui/cast.rs:524:9 | LL | (a.abs() * b.pow(2) / c.abs()) as u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:534:21 + --> tests/ui/cast.rs:532:21 | LL | let _ = i32::MIN as u32; // cast_sign_loss | ^^^^^^^^^^^^^^^ @@ -679,7 +679,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:537:21 + --> tests/ui/cast.rs:535:21 | LL | let _ = u32::MAX as u8; // cast_possible_truncation | ^^^^^^^^^^^^^^ @@ -696,7 +696,7 @@ LL + let _ = u8::try_from(u32::MAX); // cast_possible_truncation | error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:540:21 + --> tests/ui/cast.rs:538:21 | LL | let _ = std::f64::consts::PI as f32; // cast_possible_truncation | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -708,7 +708,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:551:5 + --> tests/ui/cast.rs:549:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -721,13 +721,13 @@ LL + usize::try_from(bar.unwrap().unwrap()) | error: casting `i64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:551:5 + --> tests/ui/cast.rs:549:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:568:5 + --> tests/ui/cast.rs:566:5 | LL | (256 & 999999u64) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -740,7 +740,7 @@ LL + u8::try_from(256 & 999999u64); | error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:571:5 + --> tests/ui/cast.rs:569:5 | LL | (255 % 999999u64) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs b/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs index 5dffddc119aa..cf37a4c5c4bb 100644 --- a/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs +++ b/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs @@ -1,6 +1,3 @@ -#![feature(repr128)] -#![allow(incomplete_features)] - extern crate proc_macro; use proc_macro::{Delimiter, Group, Ident, Span, TokenStream, TokenTree}; diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 1d0ddd56eec5..3e9d79224fdd 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -939,7 +939,6 @@ ui/enum-discriminant/auxiliary/issue-41394.rs ui/enum-discriminant/issue-104519.rs ui/enum-discriminant/issue-41394-rpass.rs ui/enum-discriminant/issue-41394.rs -ui/enum-discriminant/issue-43398.rs ui/enum-discriminant/issue-46519.rs ui/enum-discriminant/issue-50689.rs ui/enum-discriminant/issue-51582.rs diff --git a/tests/codegen/enum/enum-u128.rs b/tests/codegen/enum/enum-u128.rs index ecdff3c5ce31..2676669f3e30 100644 --- a/tests/codegen/enum/enum-u128.rs +++ b/tests/codegen/enum/enum-u128.rs @@ -13,9 +13,6 @@ // CHECK: {{.*}}DIEnumerator{{.*}}name: "Hi",{{.*}}value: 18446744073709551616,{{.*}} // CHECK: {{.*}}DIEnumerator{{.*}}name: "Bar",{{.*}}value: 18446745000000000123,{{.*}} -#![allow(incomplete_features)] -#![feature(repr128)] - #[repr(u128)] pub enum Foo { Lo, diff --git a/tests/debuginfo/msvc-pretty-enums.rs b/tests/debuginfo/msvc-pretty-enums.rs index 06bc25dc5d59..aa6629ef1e1b 100644 --- a/tests/debuginfo/msvc-pretty-enums.rs +++ b/tests/debuginfo/msvc-pretty-enums.rs @@ -231,8 +231,6 @@ // cdb-command: dx c_style_i128_d // cdb-check: c_style_i128_d : D [Type: enum2$] #![feature(rustc_attrs)] -#![feature(repr128)] -#![feature(arbitrary_enum_discriminant)] use std::num::NonZero; diff --git a/tests/mir-opt/enum_opt.rs b/tests/mir-opt/enum_opt.rs index e42be8ac06dc..81390567c2bb 100644 --- a/tests/mir-opt/enum_opt.rs +++ b/tests/mir-opt/enum_opt.rs @@ -3,8 +3,6 @@ // EMIT_MIR_FOR_EACH_BIT_WIDTH //@ compile-flags: -Zunsound-mir-opts -Zdump-mir-exclude-alloc-bytes -#![feature(arbitrary_enum_discriminant, repr128)] - // Tests that an enum with a variant with no data gets correctly transformed. pub enum NoData { Large([u8; 8196]), diff --git a/tests/mir-opt/matches_reduce_branches.rs b/tests/mir-opt/matches_reduce_branches.rs index 3372ae2f2a61..00131b0116db 100644 --- a/tests/mir-opt/matches_reduce_branches.rs +++ b/tests/mir-opt/matches_reduce_branches.rs @@ -1,6 +1,5 @@ //@ test-mir-pass: MatchBranchSimplification -#![feature(repr128)] #![feature(core_intrinsics)] #![feature(custom_mir)] #![allow(non_camel_case_types)] diff --git a/tests/run-make/repr128-dwarf/main.rs b/tests/run-make/repr128-dwarf/main.rs index 9842ab4a3426..a8a414fd72e4 100644 --- a/tests/run-make/repr128-dwarf/main.rs +++ b/tests/run-make/repr128-dwarf/main.rs @@ -1,5 +1,3 @@ -#![feature(repr128)] - // Use .to_le() to ensure that the bytes are in the same order on both little- and big-endian // platforms. diff --git a/tests/rustdoc-json/enums/discriminant/limits.rs b/tests/rustdoc-json/enums/discriminant/limits.rs index c84181334e35..e98271b7c806 100644 --- a/tests/rustdoc-json/enums/discriminant/limits.rs +++ b/tests/rustdoc-json/enums/discriminant/limits.rs @@ -1,6 +1,3 @@ -#![feature(repr128)] -#![allow(incomplete_features)] - #[repr(u64)] pub enum U64 { //@ is "$.index[?(@.name=='U64Min')].inner.variant.discriminant.value" '"0"' diff --git a/tests/ui/enum-discriminant/discriminant_size.rs b/tests/ui/enum-discriminant/discriminant_size.rs index a3ec1b28e5c7..b1feff3c59e1 100644 --- a/tests/ui/enum-discriminant/discriminant_size.rs +++ b/tests/ui/enum-discriminant/discriminant_size.rs @@ -1,6 +1,5 @@ //@ run-pass -#![feature(core_intrinsics, repr128)] -//~^ WARN the feature `repr128` is incomplete +#![feature(core_intrinsics)] use std::intrinsics::discriminant_value; diff --git a/tests/ui/enum-discriminant/discriminant_size.stderr b/tests/ui/enum-discriminant/discriminant_size.stderr deleted file mode 100644 index 9b1505b5c468..000000000000 --- a/tests/ui/enum-discriminant/discriminant_size.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `repr128` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/discriminant_size.rs:2:29 - | -LL | #![feature(core_intrinsics, repr128)] - | ^^^^^^^ - | - = note: see issue #56071 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/enum-discriminant/issue-43398.stderr b/tests/ui/enum-discriminant/issue-43398.stderr deleted file mode 100644 index fc7bbd062843..000000000000 --- a/tests/ui/enum-discriminant/issue-43398.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `repr128` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-43398.rs:4:12 - | -LL | #![feature(repr128)] - | ^^^^^^^ - | - = note: see issue #56071 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/enum-discriminant/issue-70509-partial_eq.rs b/tests/ui/enum-discriminant/issue-70509-partial_eq.rs index e98532c12079..5e71972c2808 100644 --- a/tests/ui/enum-discriminant/issue-70509-partial_eq.rs +++ b/tests/ui/enum-discriminant/issue-70509-partial_eq.rs @@ -1,6 +1,4 @@ //@ run-pass -#![feature(repr128)] -//~^ WARN the feature `repr128` is incomplete #[derive(PartialEq, Debug)] #[repr(i128)] diff --git a/tests/ui/enum-discriminant/issue-70509-partial_eq.stderr b/tests/ui/enum-discriminant/issue-70509-partial_eq.stderr deleted file mode 100644 index 2eef930c3943..000000000000 --- a/tests/ui/enum-discriminant/issue-70509-partial_eq.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `repr128` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-70509-partial_eq.rs:2:12 - | -LL | #![feature(repr128)] - | ^^^^^^^ - | - = note: see issue #56071 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/enum-discriminant/issue-43398.rs b/tests/ui/enum-discriminant/repr128-get-discriminant-issue-43398.rs similarity index 75% rename from tests/ui/enum-discriminant/issue-43398.rs rename to tests/ui/enum-discriminant/repr128-get-discriminant-issue-43398.rs index 574a4b3ad5a0..2bb9725fb77d 100644 --- a/tests/ui/enum-discriminant/issue-43398.rs +++ b/tests/ui/enum-discriminant/repr128-get-discriminant-issue-43398.rs @@ -1,8 +1,6 @@ //@ run-pass #![feature(core_intrinsics)] -#![feature(repr128)] -//~^ WARN the feature `repr128` is incomplete #[repr(i128)] enum Big { A, B } diff --git a/tests/ui/enum-discriminant/repr128.rs b/tests/ui/enum-discriminant/repr128.rs index 075ff7a76761..d59a5b3e256d 100644 --- a/tests/ui/enum-discriminant/repr128.rs +++ b/tests/ui/enum-discriminant/repr128.rs @@ -1,6 +1,5 @@ //@ run-pass -#![feature(repr128, core_intrinsics, discriminant_kind)] -//~^ WARN the feature `repr128` is incomplete +#![feature(core_intrinsics, discriminant_kind)] use std::intrinsics::discriminant_value; use std::marker::DiscriminantKind; diff --git a/tests/ui/enum-discriminant/repr128.stderr b/tests/ui/enum-discriminant/repr128.stderr deleted file mode 100644 index da8d75c11aff..000000000000 --- a/tests/ui/enum-discriminant/repr128.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `repr128` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/repr128.rs:2:12 - | -LL | #![feature(repr128, core_intrinsics, discriminant_kind)] - | ^^^^^^^ - | - = note: see issue #56071 for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/error-codes/E0658.rs b/tests/ui/error-codes/E0658.rs index 9c9b95d70a7c..e51674cdf92e 100644 --- a/tests/ui/error-codes/E0658.rs +++ b/tests/ui/error-codes/E0658.rs @@ -1,6 +1,3 @@ -#[repr(u128)] -enum Foo { //~ ERROR E0658 - Bar(u64), -} +use std::intrinsics; //~ ERROR E0658 fn main() {} diff --git a/tests/ui/error-codes/E0658.stderr b/tests/ui/error-codes/E0658.stderr index e1e812940ec5..ae7ecbbc5cb0 100644 --- a/tests/ui/error-codes/E0658.stderr +++ b/tests/ui/error-codes/E0658.stderr @@ -1,11 +1,10 @@ -error[E0658]: repr with 128-bit type is unstable - --> $DIR/E0658.rs:2:1 +error[E0658]: use of unstable library feature `core_intrinsics`: intrinsics are unlikely to ever be stabilized, instead they should be used through stabilized interfaces in the rest of the standard library + --> $DIR/E0658.rs:1:5 | -LL | enum Foo { - | ^^^^^^^^ +LL | use std::intrinsics; + | ^^^^^^^^^^^^^^^ | - = note: see issue #56071 for more information - = help: add `#![feature(repr128)]` to the crate attributes to enable + = help: add `#![feature(core_intrinsics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 1 previous error diff --git a/tests/ui/feature-gates/feature-gate-repr128.rs b/tests/ui/feature-gates/feature-gate-repr128.rs deleted file mode 100644 index 0290874dd27f..000000000000 --- a/tests/ui/feature-gates/feature-gate-repr128.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[repr(u128)] -enum A { //~ ERROR repr with 128-bit type is unstable - A(u64) -} - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-repr128.stderr b/tests/ui/feature-gates/feature-gate-repr128.stderr deleted file mode 100644 index 2607032447b3..000000000000 --- a/tests/ui/feature-gates/feature-gate-repr128.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: repr with 128-bit type is unstable - --> $DIR/feature-gate-repr128.rs:2:1 - | -LL | enum A { - | ^^^^^^ - | - = note: see issue #56071 for more information - = help: add `#![feature(repr128)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/lint/lint-ctypes-enum.rs b/tests/ui/lint/lint-ctypes-enum.rs index b2ef27b833bd..612da86c9568 100644 --- a/tests/ui/lint/lint-ctypes-enum.rs +++ b/tests/ui/lint/lint-ctypes-enum.rs @@ -2,8 +2,6 @@ #![deny(improper_ctypes)] #![feature(ptr_internals)] #![feature(transparent_unions)] -#![feature(repr128)] -#![allow(incomplete_features)] use std::num; diff --git a/tests/ui/lint/lint-ctypes-enum.stderr b/tests/ui/lint/lint-ctypes-enum.stderr index d5fc844f7560..50a6f526f26d 100644 --- a/tests/ui/lint/lint-ctypes-enum.stderr +++ b/tests/ui/lint/lint-ctypes-enum.stderr @@ -1,5 +1,5 @@ error: `extern` block uses type `U`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:84:14 + --> $DIR/lint-ctypes-enum.rs:82:14 | LL | fn uf(x: U); | ^ not FFI-safe @@ -7,7 +7,7 @@ LL | fn uf(x: U); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint note: the type is defined here - --> $DIR/lint-ctypes-enum.rs:11:1 + --> $DIR/lint-ctypes-enum.rs:9:1 | LL | enum U { | ^^^^^^ @@ -18,7 +18,7 @@ LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ error: `extern` block uses type `B`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:85:14 + --> $DIR/lint-ctypes-enum.rs:83:14 | LL | fn bf(x: B); | ^ not FFI-safe @@ -26,13 +26,13 @@ LL | fn bf(x: B); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint note: the type is defined here - --> $DIR/lint-ctypes-enum.rs:14:1 + --> $DIR/lint-ctypes-enum.rs:12:1 | LL | enum B { | ^^^^^^ error: `extern` block uses type `T`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:86:14 + --> $DIR/lint-ctypes-enum.rs:84:14 | LL | fn tf(x: T); | ^ not FFI-safe @@ -40,39 +40,39 @@ LL | fn tf(x: T); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint note: the type is defined here - --> $DIR/lint-ctypes-enum.rs:18:1 + --> $DIR/lint-ctypes-enum.rs:16:1 | LL | enum T { | ^^^^^^ error: `extern` block uses type `U128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:90:21 + --> $DIR/lint-ctypes-enum.rs:88:21 | LL | fn repr_u128(x: U128); | ^^^^ not FFI-safe | = note: 128-bit integers don't currently have a known stable ABI note: the type is defined here - --> $DIR/lint-ctypes-enum.rs:46:1 + --> $DIR/lint-ctypes-enum.rs:44:1 | LL | enum U128 { | ^^^^^^^^^ error: `extern` block uses type `I128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:91:21 + --> $DIR/lint-ctypes-enum.rs:89:21 | LL | fn repr_i128(x: I128); | ^^^^ not FFI-safe | = note: 128-bit integers don't currently have a known stable ABI note: the type is defined here - --> $DIR/lint-ctypes-enum.rs:53:1 + --> $DIR/lint-ctypes-enum.rs:51:1 | LL | enum I128 { | ^^^^^^^^^ error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:100:31 + --> $DIR/lint-ctypes-enum.rs:98:31 | LL | fn option_nonzero_u128(x: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -80,7 +80,7 @@ LL | fn option_nonzero_u128(x: Option>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:107:31 + --> $DIR/lint-ctypes-enum.rs:105:31 | LL | fn option_nonzero_i128(x: Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -88,7 +88,7 @@ LL | fn option_nonzero_i128(x: Option>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `Option>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:112:36 + --> $DIR/lint-ctypes-enum.rs:110:36 | LL | fn option_transparent_union(x: Option>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -97,7 +97,7 @@ LL | fn option_transparent_union(x: Option = note: enum has no representation hint error: `extern` block uses type `Option>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:114:28 + --> $DIR/lint-ctypes-enum.rs:112:28 | LL | fn option_repr_rust(x: Option>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -106,7 +106,7 @@ LL | fn option_repr_rust(x: Option>>); = note: enum has no representation hint error: `extern` block uses type `Option`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:115:21 + --> $DIR/lint-ctypes-enum.rs:113:21 | LL | fn option_u8(x: Option); | ^^^^^^^^^^ not FFI-safe @@ -115,7 +115,7 @@ LL | fn option_u8(x: Option); = note: enum has no representation hint error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:125:33 + --> $DIR/lint-ctypes-enum.rs:123:33 | LL | fn result_nonzero_u128_t(x: Result, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -123,7 +123,7 @@ LL | fn result_nonzero_u128_t(x: Result, ()>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:132:33 + --> $DIR/lint-ctypes-enum.rs:130:33 | LL | fn result_nonzero_i128_t(x: Result, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -131,7 +131,7 @@ LL | fn result_nonzero_i128_t(x: Result, ()>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `Result>, ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:137:38 + --> $DIR/lint-ctypes-enum.rs:135:38 | LL | fn result_transparent_union_t(x: Result>, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -140,7 +140,7 @@ LL | fn result_transparent_union_t(x: Result>, ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:139:30 + --> $DIR/lint-ctypes-enum.rs:137:30 | LL | fn result_repr_rust_t(x: Result>, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -149,7 +149,7 @@ LL | fn result_repr_rust_t(x: Result>, ()>); = note: enum has no representation hint error: `extern` block uses type `Result, U>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:143:51 + --> $DIR/lint-ctypes-enum.rs:141:51 | LL | fn result_1zst_exhaustive_single_variant_t(x: Result, U>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -158,7 +158,7 @@ LL | fn result_1zst_exhaustive_single_variant_t(x: Result, = note: enum has no representation hint error: `extern` block uses type `Result, B>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:145:53 + --> $DIR/lint-ctypes-enum.rs:143:53 | LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result, B>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -167,7 +167,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result = note: enum has no representation hint error: `extern` block uses type `Result, NonExhaustive>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:147:51 + --> $DIR/lint-ctypes-enum.rs:145:51 | LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result, NonExhaustive>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -176,7 +176,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result, = note: enum has no representation hint error: `extern` block uses type `Result, Field>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:150:49 + --> $DIR/lint-ctypes-enum.rs:148:49 | LL | fn result_1zst_exhaustive_single_field_t(x: Result, Field>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -185,7 +185,7 @@ LL | fn result_1zst_exhaustive_single_field_t(x: Result, Fi = note: enum has no representation hint error: `extern` block uses type `Result>, ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:152:30 + --> $DIR/lint-ctypes-enum.rs:150:30 | LL | fn result_cascading_t(x: Result>, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -194,7 +194,7 @@ LL | fn result_cascading_t(x: Result>, ()>); = note: enum has no representation hint error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:163:33 + --> $DIR/lint-ctypes-enum.rs:161:33 | LL | fn result_nonzero_u128_e(x: Result<(), num::NonZero>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -202,7 +202,7 @@ LL | fn result_nonzero_u128_e(x: Result<(), num::NonZero>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:170:33 + --> $DIR/lint-ctypes-enum.rs:168:33 | LL | fn result_nonzero_i128_e(x: Result<(), num::NonZero>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -210,7 +210,7 @@ LL | fn result_nonzero_i128_e(x: Result<(), num::NonZero>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `Result<(), TransparentUnion>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:175:38 + --> $DIR/lint-ctypes-enum.rs:173:38 | LL | fn result_transparent_union_e(x: Result<(), TransparentUnion>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -219,7 +219,7 @@ LL | fn result_transparent_union_e(x: Result<(), TransparentUnion>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:177:30 + --> $DIR/lint-ctypes-enum.rs:175:30 | LL | fn result_repr_rust_e(x: Result<(), Rust>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -228,7 +228,7 @@ LL | fn result_repr_rust_e(x: Result<(), Rust>>); = note: enum has no representation hint error: `extern` block uses type `Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:181:51 + --> $DIR/lint-ctypes-enum.rs:179:51 | LL | fn result_1zst_exhaustive_single_variant_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -237,7 +237,7 @@ LL | fn result_1zst_exhaustive_single_variant_e(x: Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:183:53 + --> $DIR/lint-ctypes-enum.rs:181:53 | LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -246,7 +246,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:185:51 + --> $DIR/lint-ctypes-enum.rs:183:51 | LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -255,7 +255,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:188:49 + --> $DIR/lint-ctypes-enum.rs:186:49 | LL | fn result_1zst_exhaustive_single_field_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -264,7 +264,7 @@ LL | fn result_1zst_exhaustive_single_field_e(x: Result>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:190:30 + --> $DIR/lint-ctypes-enum.rs:188:30 | LL | fn result_cascading_e(x: Result<(), Result<(), num::NonZero>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -273,7 +273,7 @@ LL | fn result_cascading_e(x: Result<(), Result<(), num::NonZero>>); = note: enum has no representation hint error: `extern` block uses type `Result<(), ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:192:27 + --> $DIR/lint-ctypes-enum.rs:190:27 | LL | fn result_unit_t_e(x: Result<(), ()>); | ^^^^^^^^^^^^^^ not FFI-safe diff --git a/tests/ui/transmutability/enums/repr/should_handle_all.rs b/tests/ui/transmutability/enums/repr/should_handle_all.rs index dec0126f22d4..192b7cdcf726 100644 --- a/tests/ui/transmutability/enums/repr/should_handle_all.rs +++ b/tests/ui/transmutability/enums/repr/should_handle_all.rs @@ -1,8 +1,7 @@ //@ check-pass #![crate_type = "lib"] -#![feature(repr128)] #![feature(transmutability)] -#![allow(dead_code, incomplete_features, non_camel_case_types)] +#![allow(dead_code, non_camel_case_types)] mod assert { use std::mem::{Assume, TransmuteFrom}; From 8237107d88866d4f4525f77384c653d4c80ad4df Mon Sep 17 00:00:00 2001 From: Patrick-6 Date: Wed, 28 May 2025 17:05:45 +0200 Subject: [PATCH 78/80] Add comments to diagnostic items --- library/std/src/sys/sync/mutex/futex.rs | 3 +++ library/std/src/sys/sync/mutex/pthread.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/library/std/src/sys/sync/mutex/futex.rs b/library/std/src/sys/sync/mutex/futex.rs index 01e91a6294a4..70e2ea9f6058 100644 --- a/library/std/src/sys/sync/mutex/futex.rs +++ b/library/std/src/sys/sync/mutex/futex.rs @@ -19,12 +19,14 @@ impl Mutex { } #[inline] + // Make this a diagnostic item for Miri's concurrency model checker. #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_try_lock")] pub fn try_lock(&self) -> bool { self.futex.compare_exchange(UNLOCKED, LOCKED, Acquire, Relaxed).is_ok() } #[inline] + // Make this a diagnostic item for Miri's concurrency model checker. #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_lock")] pub fn lock(&self) { if self.futex.compare_exchange(UNLOCKED, LOCKED, Acquire, Relaxed).is_err() { @@ -82,6 +84,7 @@ impl Mutex { } #[inline] + // Make this a diagnostic item for Miri's concurrency model checker. #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_unlock")] pub unsafe fn unlock(&self) { if self.futex.swap(UNLOCKED, Release) == CONTENDED { diff --git a/library/std/src/sys/sync/mutex/pthread.rs b/library/std/src/sys/sync/mutex/pthread.rs index 1d442248374d..a7a3b47d0ec6 100644 --- a/library/std/src/sys/sync/mutex/pthread.rs +++ b/library/std/src/sys/sync/mutex/pthread.rs @@ -28,6 +28,7 @@ impl Mutex { } #[inline] + // Make this a diagnostic item for Miri's concurrency model checker. #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_lock")] pub fn lock(&self) { // SAFETY: we call `init` above, therefore reentrant locking is safe. @@ -36,6 +37,7 @@ impl Mutex { } #[inline] + // Make this a diagnostic item for Miri's concurrency model checker. #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_unlock")] pub unsafe fn unlock(&self) { // SAFETY: the mutex can only be locked if it is already initialized @@ -44,6 +46,7 @@ impl Mutex { } #[inline] + // Make this a diagnostic item for Miri's concurrency model checker. #[cfg_attr(not(test), rustc_diagnostic_item = "sys_mutex_try_lock")] pub fn try_lock(&self) -> bool { // SAFETY: we call `init` above, therefore reentrant locking is safe. From 9f2ee0f4fb1420f9b49faadaed6cd021135ff354 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 28 May 2025 11:30:18 -0700 Subject: [PATCH 79/80] Add eholk to compiler reviewer rotation Now that we have work queue limits on triagebot, I'm happy to share some of the review load. --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index 12cbc926a4a8..b74159e5e5f1 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1196,6 +1196,7 @@ compiler = [ "@BoxyUwU", "@compiler-errors", "@davidtwco", + "@eholk", "@fee1-dead", "@fmease", "@jieyouxu", From afc64242b61041ee2f6e107c9483957dacfbf090 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Sat, 31 May 2025 00:30:37 +0500 Subject: [PATCH 80/80] cleaned up some tests --- tests/ui/autoderef-full-lval.rs | 25 ------------- .../autoref-autoderef/autoderef-box-no-add.rs | 35 +++++++++++++++++++ .../autoderef-box-no-add.stderr} | 4 +-- .../bare-fn-implements-fn-mut.rs | 4 +++ .../overflowing-literals-valid.rs} | 4 ++- .../vec-autoderef-autoref.rs} | 7 ++-- .../vec-autoderef-autoref.stderr} | 16 ++++----- .../str-static-literal.rs} | 2 ++ 8 files changed, 57 insertions(+), 40 deletions(-) delete mode 100644 tests/ui/autoderef-full-lval.rs create mode 100644 tests/ui/autoref-autoderef/autoderef-box-no-add.rs rename tests/ui/{autoderef-full-lval.stderr => autoref-autoderef/autoderef-box-no-add.stderr} (91%) rename tests/ui/{ => functions-closures}/bare-fn-implements-fn-mut.rs (76%) rename tests/ui/{big-literals.rs => lint/overflowing-literals-valid.rs} (84%) rename tests/ui/{auto-ref-slice-plus-ref.rs => methods/vec-autoderef-autoref.rs} (79%) rename tests/ui/{auto-ref-slice-plus-ref.stderr => methods/vec-autoderef-autoref.stderr} (83%) rename tests/ui/{bare-static-string.rs => str/str-static-literal.rs} (51%) diff --git a/tests/ui/autoderef-full-lval.rs b/tests/ui/autoderef-full-lval.rs deleted file mode 100644 index 0fadc5c98277..000000000000 --- a/tests/ui/autoderef-full-lval.rs +++ /dev/null @@ -1,25 +0,0 @@ -struct Clam { - x: Box, - y: Box, -} - - - -struct Fish { - a: Box, -} - -fn main() { - let a: Clam = Clam{ x: Box::new(1), y: Box::new(2) }; - let b: Clam = Clam{ x: Box::new(10), y: Box::new(20) }; - let z: isize = a.x + b.y; - //~^ ERROR cannot add `Box` to `Box` - println!("{}", z); - assert_eq!(z, 21); - let forty: Fish = Fish{ a: Box::new(40) }; - let two: Fish = Fish{ a: Box::new(2) }; - let answer: isize = forty.a + two.a; - //~^ ERROR cannot add `Box` to `Box` - println!("{}", answer); - assert_eq!(answer, 42); -} diff --git a/tests/ui/autoref-autoderef/autoderef-box-no-add.rs b/tests/ui/autoref-autoderef/autoderef-box-no-add.rs new file mode 100644 index 000000000000..f8085c1ae961 --- /dev/null +++ b/tests/ui/autoref-autoderef/autoderef-box-no-add.rs @@ -0,0 +1,35 @@ +//! Tests that auto-dereferencing does not allow addition of `Box` values. +//! +//! This test ensures that `Box` fields in structs (`Clam` and `Fish`) are not +//! automatically dereferenced to `isize` during addition operations, as `Box` +//! does not implement the `Add` trait. + +struct Clam { + x: Box, + y: Box, +} + +struct Fish { + a: Box, +} + +fn main() { + let a: Clam = Clam { + x: Box::new(1), + y: Box::new(2), + }; + let b: Clam = Clam { + x: Box::new(10), + y: Box::new(20), + }; + let z: isize = a.x + b.y; + //~^ ERROR cannot add `Box` to `Box` + println!("{}", z); + assert_eq!(z, 21); + let forty: Fish = Fish { a: Box::new(40) }; + let two: Fish = Fish { a: Box::new(2) }; + let answer: isize = forty.a + two.a; + //~^ ERROR cannot add `Box` to `Box` + println!("{}", answer); + assert_eq!(answer, 42); +} diff --git a/tests/ui/autoderef-full-lval.stderr b/tests/ui/autoref-autoderef/autoderef-box-no-add.stderr similarity index 91% rename from tests/ui/autoderef-full-lval.stderr rename to tests/ui/autoref-autoderef/autoderef-box-no-add.stderr index d90238a7fb21..20ef3352831a 100644 --- a/tests/ui/autoderef-full-lval.stderr +++ b/tests/ui/autoref-autoderef/autoderef-box-no-add.stderr @@ -1,5 +1,5 @@ error[E0369]: cannot add `Box` to `Box` - --> $DIR/autoderef-full-lval.rs:15:24 + --> $DIR/autoderef-box-no-add.rs:25:24 | LL | let z: isize = a.x + b.y; | --- ^ --- Box @@ -13,7 +13,7 @@ note: the foreign item type `Box` doesn't implement `Add` = note: not implement `Add` error[E0369]: cannot add `Box` to `Box` - --> $DIR/autoderef-full-lval.rs:21:33 + --> $DIR/autoderef-box-no-add.rs:31:33 | LL | let answer: isize = forty.a + two.a; | ------- ^ ----- Box diff --git a/tests/ui/bare-fn-implements-fn-mut.rs b/tests/ui/functions-closures/bare-fn-implements-fn-mut.rs similarity index 76% rename from tests/ui/bare-fn-implements-fn-mut.rs rename to tests/ui/functions-closures/bare-fn-implements-fn-mut.rs index 49b31f28f8a0..52d5ad3d0f79 100644 --- a/tests/ui/bare-fn-implements-fn-mut.rs +++ b/tests/ui/functions-closures/bare-fn-implements-fn-mut.rs @@ -1,3 +1,7 @@ +//! Tests that bare functions implement the `FnMut` trait. +//! +//! See . + //@ run-pass fn call_f(mut f: F) { diff --git a/tests/ui/big-literals.rs b/tests/ui/lint/overflowing-literals-valid.rs similarity index 84% rename from tests/ui/big-literals.rs rename to tests/ui/lint/overflowing-literals-valid.rs index d2f447a595c9..08aa092ee71e 100644 --- a/tests/ui/big-literals.rs +++ b/tests/ui/lint/overflowing-literals-valid.rs @@ -1,5 +1,7 @@ +//! Test that valid large numeric literals do not trigger the `overflowing_literals` lint. + //@ run-pass -// Catch mistakes in the overflowing literals lint. + #![deny(overflowing_literals)] pub fn main() { diff --git a/tests/ui/auto-ref-slice-plus-ref.rs b/tests/ui/methods/vec-autoderef-autoref.rs similarity index 79% rename from tests/ui/auto-ref-slice-plus-ref.rs rename to tests/ui/methods/vec-autoderef-autoref.rs index 00b279d3226c..38c0ba8574b0 100644 --- a/tests/ui/auto-ref-slice-plus-ref.rs +++ b/tests/ui/methods/vec-autoderef-autoref.rs @@ -1,8 +1,7 @@ +//! Test that method resolution does not autoderef `Vec` +//! into a slice or perform additional autorefs. + fn main() { - - // Testing that method lookup does not automatically borrow - // vectors to slices then automatically create a self reference. - let mut a = vec![0]; a.test_mut(); //~ ERROR no method named `test_mut` found a.test(); //~ ERROR no method named `test` found diff --git a/tests/ui/auto-ref-slice-plus-ref.stderr b/tests/ui/methods/vec-autoderef-autoref.stderr similarity index 83% rename from tests/ui/auto-ref-slice-plus-ref.stderr rename to tests/ui/methods/vec-autoderef-autoref.stderr index 806c1ee064ff..61c3bcc5b3b3 100644 --- a/tests/ui/auto-ref-slice-plus-ref.stderr +++ b/tests/ui/methods/vec-autoderef-autoref.stderr @@ -1,12 +1,12 @@ error[E0599]: no method named `test_mut` found for struct `Vec<{integer}>` in the current scope - --> $DIR/auto-ref-slice-plus-ref.rs:7:7 + --> $DIR/vec-autoderef-autoref.rs:6:7 | LL | a.test_mut(); | ^^^^^^^^ | = help: items from traits can only be used if the trait is implemented and in scope note: `MyIter` defines an item `test_mut`, perhaps you need to implement it - --> $DIR/auto-ref-slice-plus-ref.rs:14:1 + --> $DIR/vec-autoderef-autoref.rs:13:1 | LL | trait MyIter { | ^^^^^^^^^^^^ @@ -14,40 +14,40 @@ help: there is a method `get_mut` with a similar name, but with different argume --> $SRC_DIR/core/src/slice/mod.rs:LL:COL error[E0599]: no method named `test` found for struct `Vec<{integer}>` in the current scope - --> $DIR/auto-ref-slice-plus-ref.rs:8:7 + --> $DIR/vec-autoderef-autoref.rs:7:7 | LL | a.test(); | ^^^^ method not found in `Vec<{integer}>` | = help: items from traits can only be used if the trait is implemented and in scope note: `MyIter` defines an item `test`, perhaps you need to implement it - --> $DIR/auto-ref-slice-plus-ref.rs:14:1 + --> $DIR/vec-autoderef-autoref.rs:13:1 | LL | trait MyIter { | ^^^^^^^^^^^^ error[E0599]: no method named `test` found for array `[{integer}; 1]` in the current scope - --> $DIR/auto-ref-slice-plus-ref.rs:10:11 + --> $DIR/vec-autoderef-autoref.rs:9:11 | LL | ([1]).test(); | ^^^^ method not found in `[{integer}; 1]` | = help: items from traits can only be used if the trait is implemented and in scope note: `MyIter` defines an item `test`, perhaps you need to implement it - --> $DIR/auto-ref-slice-plus-ref.rs:14:1 + --> $DIR/vec-autoderef-autoref.rs:13:1 | LL | trait MyIter { | ^^^^^^^^^^^^ error[E0599]: no method named `test` found for reference `&[{integer}; 1]` in the current scope - --> $DIR/auto-ref-slice-plus-ref.rs:11:12 + --> $DIR/vec-autoderef-autoref.rs:10:12 | LL | (&[1]).test(); | ^^^^ method not found in `&[{integer}; 1]` | = help: items from traits can only be used if the trait is implemented and in scope note: `MyIter` defines an item `test`, perhaps you need to implement it - --> $DIR/auto-ref-slice-plus-ref.rs:14:1 + --> $DIR/vec-autoderef-autoref.rs:13:1 | LL | trait MyIter { | ^^^^^^^^^^^^ diff --git a/tests/ui/bare-static-string.rs b/tests/ui/str/str-static-literal.rs similarity index 51% rename from tests/ui/bare-static-string.rs rename to tests/ui/str/str-static-literal.rs index b71cf38cfe81..61630f0f22bd 100644 --- a/tests/ui/bare-static-string.rs +++ b/tests/ui/str/str-static-literal.rs @@ -1,3 +1,5 @@ +//! Check that a bare string literal is typed as a `&'static str` and is usable. + //@ run-pass pub fn main() {