From 797b6c94ccfc442a450585eb6fb12466498b4014 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 1 Sep 2026 01:09:11 +0200 Subject: [PATCH 01/29] remove deprecated/remove/rustdoc_internal doc attributes from suggestions --- compiler/rustc_attr_parsing/src/attributes/doc.rs | 12 +----------- tests/rustdoc-ui/lints/invalid-doc-attr-2.stderr | 2 +- tests/ui/attributes/malformed-attrs.stderr | 4 ++-- tests/ui/malformed/malformed-regressions.stderr | 2 +- 4 files changed, 5 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index e315d6abea395..9c8457458cfe7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -749,7 +749,6 @@ impl AttributeParser for DocParser { template!( List: &[ "alias", - "attribute", "hidden", "html_favicon_url", "html_logo_url", @@ -762,19 +761,10 @@ impl AttributeParser for DocParser { "masked", "cfg", "notable_trait", - "keyword", - "fake_variadic", - "search_unbox", - "rust_logo", "auto_cfg", "test", - "spotlight", - "include", - "no_default_passes", - "passes", - "plugins", ], - NameValueStr: "string" + NameValueStr: "doc comment" ), AttributeStability::Stable, // Some parts of the attribute are unstable, manually checked in parser |this, cx, args| { diff --git a/tests/rustdoc-ui/lints/invalid-doc-attr-2.stderr b/tests/rustdoc-ui/lints/invalid-doc-attr-2.stderr index 661b9eae9ce9b..0285af4108ef0 100644 --- a/tests/rustdoc-ui/lints/invalid-doc-attr-2.stderr +++ b/tests/rustdoc-ui/lints/invalid-doc-attr-2.stderr @@ -11,7 +11,7 @@ note: the lint level is defined here LL | #![deny(invalid_doc_attributes)] | ^^^^^^^^^^^^^^^^^^^^^^ -error: valid forms for the attribute are `doc = "string"`, `doc(alias)`, `doc(attribute)`, `doc(auto_cfg)`, `doc(cfg)`, `doc(fake_variadic)`, `doc(hidden)`, `doc(html_favicon_url)`, `doc(html_logo_url)`, `doc(html_no_source)`, `doc(html_playground_url)`, `doc(html_root_url)`, `doc(include)`, `doc(inline)`, `doc(issue_tracker_base_url)`, `doc(keyword)`, `doc(masked)`, `doc(no_default_passes)`, `doc(no_inline)`, `doc(notable_trait)`, `doc(passes)`, `doc(plugins)`, `doc(rust_logo)`, `doc(search_unbox)`, `doc(spotlight)`, and `doc(test)` +error: valid forms for the attribute are `doc = "doc comment"`, `doc(alias)`, `doc(auto_cfg)`, `doc(cfg)`, `doc(hidden)`, `doc(html_favicon_url)`, `doc(html_logo_url)`, `doc(html_no_source)`, `doc(html_playground_url)`, `doc(html_root_url)`, `doc(inline)`, `doc(issue_tracker_base_url)`, `doc(masked)`, `doc(no_inline)`, `doc(notable_trait)`, and `doc(test)` --> $DIR/invalid-doc-attr-2.rs:6:4 | LL | #![doc] diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 213e017a6be4d..af6cff2d02ca7 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -852,7 +852,7 @@ LL | | #[coroutine = 63] || {} LL | | } | |_- not a `const fn` -error: valid forms for the attribute are `doc = "string"`, `doc(alias)`, `doc(attribute)`, `doc(auto_cfg)`, `doc(cfg)`, `doc(fake_variadic)`, `doc(hidden)`, `doc(html_favicon_url)`, `doc(html_logo_url)`, `doc(html_no_source)`, `doc(html_playground_url)`, `doc(html_root_url)`, `doc(include)`, `doc(inline)`, `doc(issue_tracker_base_url)`, `doc(keyword)`, `doc(masked)`, `doc(no_default_passes)`, `doc(no_inline)`, `doc(notable_trait)`, `doc(passes)`, `doc(plugins)`, `doc(rust_logo)`, `doc(search_unbox)`, `doc(spotlight)`, and `doc(test)` +error: valid forms for the attribute are `doc = "doc comment"`, `doc(alias)`, `doc(auto_cfg)`, `doc(cfg)`, `doc(hidden)`, `doc(html_favicon_url)`, `doc(html_logo_url)`, `doc(html_no_source)`, `doc(html_playground_url)`, `doc(html_root_url)`, `doc(inline)`, `doc(issue_tracker_base_url)`, `doc(masked)`, `doc(no_inline)`, `doc(notable_trait)`, and `doc(test)` --> $DIR/malformed-attrs.rs:41:3 | LL | #[doc] @@ -890,7 +890,7 @@ LL | | } | |_^ = note: requested on the command line with `-W unused-attributes` -error: valid forms for the attribute are `doc = "string"`, `doc(alias)`, `doc(attribute)`, `doc(auto_cfg)`, `doc(cfg)`, `doc(fake_variadic)`, `doc(hidden)`, `doc(html_favicon_url)`, `doc(html_logo_url)`, `doc(html_no_source)`, `doc(html_playground_url)`, `doc(html_root_url)`, `doc(include)`, `doc(inline)`, `doc(issue_tracker_base_url)`, `doc(keyword)`, `doc(masked)`, `doc(no_default_passes)`, `doc(no_inline)`, `doc(notable_trait)`, `doc(passes)`, `doc(plugins)`, `doc(rust_logo)`, `doc(search_unbox)`, `doc(spotlight)`, and `doc(test)` +error: valid forms for the attribute are `doc = "doc comment"`, `doc(alias)`, `doc(auto_cfg)`, `doc(cfg)`, `doc(hidden)`, `doc(html_favicon_url)`, `doc(html_logo_url)`, `doc(html_no_source)`, `doc(html_playground_url)`, `doc(html_root_url)`, `doc(inline)`, `doc(issue_tracker_base_url)`, `doc(masked)`, `doc(no_inline)`, `doc(notable_trait)`, and `doc(test)` --> $DIR/malformed-attrs.rs:79:3 | LL | #[doc] diff --git a/tests/ui/malformed/malformed-regressions.stderr b/tests/ui/malformed/malformed-regressions.stderr index 693b16c610bb2..0dcdee9ccc990 100644 --- a/tests/ui/malformed/malformed-regressions.stderr +++ b/tests/ui/malformed/malformed-regressions.stderr @@ -16,7 +16,7 @@ LL | #[link = ""] | = note: for more information, visit -error: valid forms for the attribute are `doc = "string"`, `doc(alias)`, `doc(attribute)`, `doc(auto_cfg)`, `doc(cfg)`, `doc(fake_variadic)`, `doc(hidden)`, `doc(html_favicon_url)`, `doc(html_logo_url)`, `doc(html_no_source)`, `doc(html_playground_url)`, `doc(html_root_url)`, `doc(include)`, `doc(inline)`, `doc(issue_tracker_base_url)`, `doc(keyword)`, `doc(masked)`, `doc(no_default_passes)`, `doc(no_inline)`, `doc(notable_trait)`, `doc(passes)`, `doc(plugins)`, `doc(rust_logo)`, `doc(search_unbox)`, `doc(spotlight)`, and `doc(test)` +error: valid forms for the attribute are `doc = "doc comment"`, `doc(alias)`, `doc(auto_cfg)`, `doc(cfg)`, `doc(hidden)`, `doc(html_favicon_url)`, `doc(html_logo_url)`, `doc(html_no_source)`, `doc(html_playground_url)`, `doc(html_root_url)`, `doc(inline)`, `doc(issue_tracker_base_url)`, `doc(masked)`, `doc(no_inline)`, `doc(notable_trait)`, and `doc(test)` --> $DIR/malformed-regressions.rs:3:3 | LL | #[doc] From 25e99b23be7c1283d3ad397931ee63500f14b4f9 Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 1 Sep 2026 01:33:18 +0200 Subject: [PATCH 02/29] Warn on `#[doc()]` --- .../rustc_attr_parsing/src/attributes/doc.rs | 20 +++---- tests/ui/attributes/malformed-attrs.rs | 4 +- tests/ui/attributes/malformed-attrs.stderr | 52 +++++++++---------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 9c8457458cfe7..c962e75fda17f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -705,16 +705,7 @@ impl DocParser { fn accept_single_doc_attr(&mut self, cx: &mut AcceptContext<'_, '_>, args: &ArgParser) { match args { - ArgParser::NoArgs => { - let suggestions = cx.adcx().suggestions(); - let span = cx.inner_span; - cx.emit_lint( - INVALID_DOC_ATTRIBUTES, - IllFormedAttributeInput::new(&suggestions, None, None), - span, - ); - } - ArgParser::List(items) => { + ArgParser::List(items) if !items.is_empty() => { for i in items.mixed() { match i { MetaItemOrLitParser::MetaItemParser(mip) => { @@ -739,6 +730,15 @@ impl DocParser { ); } } + _ => { + let suggestions = cx.adcx().suggestions(); + let span = cx.inner_span; + cx.emit_lint( + INVALID_DOC_ATTRIBUTES, + IllFormedAttributeInput::new(&suggestions, None, None), + span, + ); + } } } } diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs index d5f663020f3e0..36ad21a54bd51 100644 --- a/tests/ui/attributes/malformed-attrs.rs +++ b/tests/ui/attributes/malformed-attrs.rs @@ -40,6 +40,8 @@ //~^ ERROR malformed #[doc] //~^ ERROR +#[doc()] +//~^ ERROR #[rustc_macro_transparency] //~^ ERROR malformed //~| ERROR attribute cannot be used on @@ -76,8 +78,6 @@ #[crate_name] //~^ ERROR malformed //~| WARN crate-level attribute should be an inner attribute -#[doc] -//~^ ERROR #[target_feature] //~^ ERROR malformed #[export_stable = 1] diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index af6cff2d02ca7..72e7776e09209 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -191,7 +191,7 @@ LL | #[deprecated = 5] | expected a string literal here error[E0539]: malformed `rustc_macro_transparency` attribute input - --> $DIR/malformed-attrs.rs:43:3 + --> $DIR/malformed-attrs.rs:45:3 | LL | #[rustc_macro_transparency] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -206,7 +206,7 @@ LL | #[rustc_macro_transparency = "transparent"] | +++++++++++++++ error: the `rustc_macro_transparency` attribute cannot be used on functions - --> $DIR/malformed-attrs.rs:43:3 + --> $DIR/malformed-attrs.rs:45:3 | LL | #[rustc_macro_transparency] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -214,7 +214,7 @@ LL | #[rustc_macro_transparency] = help: the `rustc_macro_transparency` attribute can only be applied to macro defs error[E0539]: malformed `repr` attribute input - --> $DIR/malformed-attrs.rs:46:3 + --> $DIR/malformed-attrs.rs:48:3 | LL | #[repr] | ^^^^ expected this to be a list @@ -222,7 +222,7 @@ LL | #[repr] = note: for more information, visit error[E0565]: malformed `rustc_as_ptr` attribute input - --> $DIR/malformed-attrs.rs:48:3 + --> $DIR/malformed-attrs.rs:50:3 | LL | #[rustc_as_ptr = 5] | ^^^^^^^^^^^^^--- @@ -236,7 +236,7 @@ LL + #[rustc_as_ptr] | error[E0539]: malformed `rustc_align` attribute input - --> $DIR/malformed-attrs.rs:53:3 + --> $DIR/malformed-attrs.rs:55:3 | LL | #[rustc_align] | ^^^^^^^^^^^ expected this to be a list @@ -247,7 +247,7 @@ LL | #[rustc_align()] | ++++++++++++++++++++++ error[E0539]: malformed `optimize` attribute input - --> $DIR/malformed-attrs.rs:55:3 + --> $DIR/malformed-attrs.rs:57:3 | LL | #[optimize] | ^^^^^^^^ expected this to be a list @@ -262,7 +262,7 @@ LL | #[optimize(speed)] | +++++++ error[E0805]: malformed `optimize` attribute input - --> $DIR/malformed-attrs.rs:57:3 + --> $DIR/malformed-attrs.rs:59:3 | LL | #[optimize(none, none)] | ^^^^^^^^------------ @@ -282,7 +282,7 @@ LL + #[optimize(speed)] | error[E0805]: malformed `optimize` attribute input - --> $DIR/malformed-attrs.rs:59:3 + --> $DIR/malformed-attrs.rs:61:3 | LL | #[optimize(none, speed)] | ^^^^^^^^------------- @@ -302,7 +302,7 @@ LL + #[optimize(speed)] | error[E0565]: malformed `cold` attribute input - --> $DIR/malformed-attrs.rs:61:3 + --> $DIR/malformed-attrs.rs:63:3 | LL | #[cold = 1] | ^^^^^--- @@ -316,7 +316,7 @@ LL + #[cold] | error[E0539]: malformed `must_use` attribute input - --> $DIR/malformed-attrs.rs:63:3 + --> $DIR/malformed-attrs.rs:65:3 | LL | #[must_use()] | ^^^^^^^^-- @@ -334,7 +334,7 @@ LL + #[must_use = "reason"] | error[E0565]: malformed `no_mangle` attribute input - --> $DIR/malformed-attrs.rs:65:3 + --> $DIR/malformed-attrs.rs:67:3 | LL | #[no_mangle = 1] | ^^^^^^^^^^--- @@ -348,7 +348,7 @@ LL + #[no_mangle] | error[E0565]: malformed `naked` attribute input - --> $DIR/malformed-attrs.rs:67:3 + --> $DIR/malformed-attrs.rs:69:3 | LL | #[unsafe(naked())] | ^^^^^^^^^^^^--^ @@ -362,7 +362,7 @@ LL + #[unsafe(naked)] | error[E0565]: malformed `track_caller` attribute input - --> $DIR/malformed-attrs.rs:69:3 + --> $DIR/malformed-attrs.rs:71:3 | LL | #[track_caller()] | ^^^^^^^^^^^^-- @@ -376,7 +376,7 @@ LL + #[track_caller] | error[E0539]: malformed `export_name` attribute input - --> $DIR/malformed-attrs.rs:71:3 + --> $DIR/malformed-attrs.rs:73:3 | LL | #[export_name()] | ^^^^^^^^^^^^^ @@ -388,7 +388,7 @@ LL + #[export_name = "name"] | error[E0805]: malformed `used` attribute input - --> $DIR/malformed-attrs.rs:73:3 + --> $DIR/malformed-attrs.rs:75:3 | LL | #[used()] | ^^^^-- @@ -406,7 +406,7 @@ LL | #[used(linker)] | ++++++ error: the `used` attribute cannot be used on functions - --> $DIR/malformed-attrs.rs:73:3 + --> $DIR/malformed-attrs.rs:75:3 | LL | #[used()] | ^^^^ @@ -414,7 +414,7 @@ LL | #[used()] = help: the `used` attribute can only be applied to statics error[E0539]: malformed `crate_name` attribute input - --> $DIR/malformed-attrs.rs:76:3 + --> $DIR/malformed-attrs.rs:78:3 | LL | #[crate_name] | ^^^^^^^^^^ @@ -864,8 +864,14 @@ note: the lint level is defined here LL | #![deny(invalid_doc_attributes)] | ^^^^^^^^^^^^^^^^^^^^^^ +error: valid forms for the attribute are `doc = "doc comment"`, `doc(alias)`, `doc(auto_cfg)`, `doc(cfg)`, `doc(hidden)`, `doc(html_favicon_url)`, `doc(html_logo_url)`, `doc(html_no_source)`, `doc(html_playground_url)`, `doc(html_root_url)`, `doc(inline)`, `doc(issue_tracker_base_url)`, `doc(masked)`, `doc(no_inline)`, `doc(notable_trait)`, and `doc(test)` + --> $DIR/malformed-attrs.rs:43:3 + | +LL | #[doc()] + | ^^^^^ + error: valid forms for the attribute are `inline`, `inline(always)`, and `inline(never)` - --> $DIR/malformed-attrs.rs:50:3 + --> $DIR/malformed-attrs.rs:52:3 | LL | #[inline = 5] | ^^^^^^^^^^ @@ -875,7 +881,7 @@ LL | #[inline = 5] = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![crate_name]` - --> $DIR/malformed-attrs.rs:76:1 + --> $DIR/malformed-attrs.rs:78:1 | LL | #[crate_name] | ^^^^^^^^^^^^^ @@ -890,12 +896,6 @@ LL | | } | |_^ = note: requested on the command line with `-W unused-attributes` -error: valid forms for the attribute are `doc = "doc comment"`, `doc(alias)`, `doc(auto_cfg)`, `doc(cfg)`, `doc(hidden)`, `doc(html_favicon_url)`, `doc(html_logo_url)`, `doc(html_no_source)`, `doc(html_playground_url)`, `doc(html_root_url)`, `doc(inline)`, `doc(issue_tracker_base_url)`, `doc(masked)`, `doc(no_inline)`, `doc(notable_trait)`, and `doc(test)` - --> $DIR/malformed-attrs.rs:79:3 - | -LL | #[doc] - | ^^^ - warning: the `link` attribute cannot be used on functions --> $DIR/malformed-attrs.rs:85:3 | @@ -990,7 +990,7 @@ Some errors have detailed explanations: E0308, E0463, E0539, E0565, E0658, E0805 For more information about an error, try `rustc --explain E0308`. Future incompatibility report: Future breakage diagnostic: error: valid forms for the attribute are `inline`, `inline(always)`, and `inline(never)` - --> $DIR/malformed-attrs.rs:50:3 + --> $DIR/malformed-attrs.rs:52:3 | LL | #[inline = 5] | ^^^^^^^^^^ From da1a5df7dcdb417e7033ccf3247ff5cfd64e5890 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Mon, 24 Aug 2026 13:02:57 +0000 Subject: [PATCH 03/29] take `&Item` instead of `Annotatable` as derive macro input --- .../src/deriving/bounds.rs | 4 +- .../src/deriving/clone.rs | 51 ++++----- .../src/deriving/cmp/eq.rs | 2 +- .../src/deriving/cmp/ord.rs | 2 +- .../src/deriving/cmp/partial_eq.rs | 2 +- .../src/deriving/cmp/partial_ord.rs | 49 ++++----- .../src/deriving/coerce_pointee.rs | 10 +- .../src/deriving/debug.rs | 2 +- .../src/deriving/default.rs | 12 +- .../rustc_builtin_macros/src/deriving/from.rs | 8 +- .../src/deriving/generic/mod.rs | 103 ++++++++---------- .../rustc_builtin_macros/src/deriving/hash.rs | 2 +- .../rustc_builtin_macros/src/deriving/mod.rs | 9 +- .../src/deriving/reborrow.rs | 39 +++---- 14 files changed, 130 insertions(+), 165 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 48fdb4dd39ce2..5b71d38c63e2e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -9,7 +9,7 @@ pub(crate) fn expand_deriving_copy( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, + item: &ast::Item, push: &mut dyn FnMut(Annotatable), is_const: bool, ) { @@ -34,7 +34,7 @@ pub(crate) fn expand_deriving_const_param_ty( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, + item: &ast::Item, push: &mut dyn FnMut(Annotatable), is_const: bool, ) { diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index b4374e32f6051..be70cf0b584a1 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -12,7 +12,7 @@ pub(crate) fn expand_deriving_clone( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, + item: &ast::Item, push: &mut dyn FnMut(Annotatable), is_const: bool, ) { @@ -32,35 +32,30 @@ pub(crate) fn expand_deriving_clone( let bounds; let substructure; let is_simple; - match item { - Annotatable::Item(annitem) => match &annitem.kind { - 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); - bounds = smallvec![]; - if has_derive_copy - && !params - .iter() - .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) - { - is_simple = true; - substructure = - combine_substructure(|c, s, sub| cs_clone_simple(c, s, sub, false)); - } else { - is_simple = false; - substructure = combine_substructure(cs_clone); - } - } - ItemKind::Union(..) => { - bounds = smallvec![Path(path_std!(marker::Copy))]; + match &item.kind { + 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); + bounds = smallvec![]; + if has_derive_copy + && !params + .iter() + .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) + { is_simple = true; - substructure = combine_substructure(|c, s, sub| cs_clone_simple(c, s, sub, true)); + substructure = combine_substructure(|c, s, sub| cs_clone_simple(c, s, sub, false)); + } else { + is_simple = false; + substructure = combine_substructure(cs_clone); } - _ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on wrong item kind"), - }, - - _ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on trait item or impl item"), + } + ItemKind::Union(..) => { + bounds = smallvec![Path(path_std!(marker::Copy))]; + is_simple = true; + substructure = combine_substructure(|c, s, sub| cs_clone_simple(c, s, sub, true)); + } + _ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on wrong item kind"), } // If the clone method is just copying the value, also mark the type as diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 440360ca85d7d..0df5767e2bde0 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -12,7 +12,7 @@ pub(crate) fn expand_deriving_eq( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, + item: &ast::Item, push: &mut dyn FnMut(Annotatable), is_const: bool, ) { diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index a1b38ceadb228..84e5485020a1f 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -11,7 +11,7 @@ pub(crate) fn expand_deriving_ord( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, + item: &ast::Item, push: &mut dyn FnMut(Annotatable), is_const: bool, ) { diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index b852e29b03ca4..fb3d6e9b338f7 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -13,7 +13,7 @@ pub(crate) fn expand_deriving_partial_eq( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, + item: &ast::Item, push: &mut dyn FnMut(Annotatable), is_const: bool, ) { 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 88141224fddc2..8b778a014ade0 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -11,7 +11,7 @@ pub(crate) fn expand_deriving_partial_ord( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, + item: &ast::Item, push: &mut dyn FnMut(Annotatable), is_const: bool, ) { @@ -20,9 +20,7 @@ pub(crate) fn expand_deriving_partial_ord( Path(Path::new_(pathvec!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std)); // Order in which to perform matching - let discr_then_data = if let Annotatable::Item(item) = item - && let ItemKind::Enum(_, _, def) = &item.kind - { + let discr_then_data = if 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() { // No data, placing the discriminant check first makes codegen simpler @@ -49,29 +47,26 @@ pub(crate) fn expand_deriving_partial_ord( let simple_substructure = combine_substructure(|cx, span, _| { cs_partial_cmp_simple(cx, span, cx.expr_ident(span, Ident::new(sym::other, span))) }); - let is_simple = match item { - Annotatable::Item(annitem) => match &annitem.kind { - // For unit structs/zero-variant enums, the default generated code is better. - ItemKind::Struct(.., ast::VariantData::Unit(..)) => false, - // Also for single fieldless variant enum - ItemKind::Enum(.., enum_def) if enum_def.variants.is_empty() => false, - ItemKind::Enum(.., enum_def) - if enum_def.variants.len() == 1 - && matches!(enum_def.variants[0].data, ast::VariantData::Unit(..)) => - { - false - } - ItemKind::Struct(_, ast::Generics { params, .. }, _) - | ItemKind::Enum(_, ast::Generics { params, .. }, _) - if has_derive_ord - && !params - .iter() - .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) => - { - true - } - _ => false, - }, + let is_simple = match &item.kind { + // For unit structs/zero-variant enums, the default generated code is better. + ItemKind::Struct(.., ast::VariantData::Unit(..)) => false, + // Also for single fieldless variant enum + ItemKind::Enum(.., enum_def) if enum_def.variants.is_empty() => false, + ItemKind::Enum(.., enum_def) + if enum_def.variants.len() == 1 + && matches!(enum_def.variants[0].data, ast::VariantData::Unit(..)) => + { + false + } + ItemKind::Struct(_, ast::Generics { params, .. }, _) + | ItemKind::Enum(_, ast::Generics { params, .. }, _) + if has_derive_ord + && !params + .iter() + .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })) => + { + true + } _ => false, }; diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index 80296a43ee490..a18af8e035c68 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -1,6 +1,6 @@ use ast::HasAttrs; use rustc_ast::mut_visit::MutVisitor; -use rustc_ast::visit::BoundKind; +use rustc_ast::visit::{BoundKind, Visitor}; use rustc_ast::{ self as ast, GenericArg, GenericBound, GenericParamKind, Generics, ItemKind, MetaItem, TraitBoundModifiers, VariantData, WherePredicate, @@ -22,15 +22,13 @@ pub(crate) fn expand_deriving_coerce_pointee( cx: &ExtCtxt<'_>, span: Span, _mitem: &MetaItem, - item: &Annotatable, + item: &ast::Item, push: &mut dyn FnMut(Annotatable), _is_const: bool, ) { - item.visit_with(&mut DetectNonGenericPointeeAttr { cx }); + DetectNonGenericPointeeAttr { cx }.visit_item(item); - let (name_ident, generics) = if let Annotatable::Item(aitem) = item - && let ItemKind::Struct(ident, g, struct_data) = &aitem.kind - { + let (name_ident, generics) = if let ItemKind::Struct(ident, g, struct_data) = &item.kind { if !matches!( struct_data, VariantData::Struct { fields, recovered: _ } | VariantData::Tuple(fields, _) diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 94e0b704e6c08..74dd639298d1c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -12,7 +12,7 @@ pub(crate) fn expand_deriving_debug( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, + item: &ast::Item, push: &mut dyn FnMut(Annotatable), is_const: bool, ) { diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 3e4c5f1dcfa53..4293c89d15f96 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -1,6 +1,6 @@ use core::ops::ControlFlow; -use rustc_ast::visit::visit_opt; +use rustc_ast::visit::{Visitor, visit_opt}; use rustc_ast::{self as ast, EnumDef, Safety, VariantData, attr}; use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym}; @@ -15,11 +15,11 @@ pub(crate) fn expand_deriving_default( cx: &ExtCtxt<'_>, span: Span, mitem: &ast::MetaItem, - item: &Annotatable, + item: &ast::Item, push: &mut dyn FnMut(Annotatable), is_const: bool, ) { - item.visit_with(&mut DetectNonVariantDefaultAttr { cx }); + DetectNonVariantDefaultAttr { cx }.visit_item(item); let trait_def = TraitDef { span, @@ -42,7 +42,7 @@ pub(crate) fn expand_deriving_default( default_struct_substructure(cx, trait_span, substr, fields) } StaticEnum(enum_def) => { - default_enum_substructure(cx, trait_span, enum_def, item.span()) + default_enum_substructure(cx, trait_span, enum_def, item.span) } _ => cx.dcx().span_bug(trait_span, "method in `derive(Default)`"), } @@ -308,7 +308,7 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, ' } } -fn has_a_default_variant(item: &Annotatable) -> bool { +fn has_a_default_variant(item: &ast::Item) -> bool { struct HasDefaultAttrOnVariant; impl<'ast> rustc_ast::visit::Visitor<'ast> for HasDefaultAttrOnVariant { @@ -323,5 +323,5 @@ fn has_a_default_variant(item: &Annotatable) -> bool { } } - item.visit_with(&mut HasDefaultAttrOnVariant).is_break() + HasDefaultAttrOnVariant.visit_item(item).is_break() } diff --git a/compiler/rustc_builtin_macros/src/deriving/from.rs b/compiler/rustc_builtin_macros/src/deriving/from.rs index 9824ab5a225b7..4f7d7fe15b616 100644 --- a/compiler/rustc_builtin_macros/src/deriving/from.rs +++ b/compiler/rustc_builtin_macros/src/deriving/from.rs @@ -16,14 +16,10 @@ pub(crate) fn expand_deriving_from( cx: &ExtCtxt<'_>, span: Span, mitem: &ast::MetaItem, - annotatable: &Annotatable, + item: &ast::Item, push: &mut dyn FnMut(Annotatable), is_const: bool, ) { - let Annotatable::Item(item) = &annotatable else { - cx.dcx().bug("derive(From) used on something else than an item"); - }; - let err_span = || { let item_span = item.kind.ident().map(|ident| ident.span).unwrap_or(item.span); MultiSpan::from_spans(vec![span, item_span]) @@ -127,5 +123,5 @@ pub(crate) fn expand_deriving_from( document: true, }; - from_trait_def.expand(cx, mitem, annotatable, push); + from_trait_def.expand(cx, mitem, item, push); } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 6a53dafd396df..cfd336fafc4a9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -179,10 +179,11 @@ use std::{iter, vec}; pub(crate) use StaticFields::*; pub(crate) use SubstructureFields::*; +pub(crate) use rustc_ast as ast; use rustc_ast::token::{IdentIsRaw, LitKind, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenTree}; use rustc_ast::{ - self as ast, AnonConst, AttrArgs, BindingMode, ByRef, DelimArgs, EnumDef, Expr, GenericArg, + AnonConst, AttrArgs, BindingMode, ByRef, DelimArgs, EnumDef, Expr, GenericArg, GenericParamKind, Generics, Mutability, PatKind, Safety, SelfKind, VariantData, }; use rustc_attr_ir::{Attribute, AttributeKind, ReprPacked}; @@ -473,7 +474,7 @@ impl<'a> TraitDef<'a> { self, cx: &ExtCtxt<'_>, mitem: &ast::MetaItem, - item: &'a Annotatable, + item: &'a ast::Item, push: &mut dyn FnMut(Annotatable), ) { self.expand_ext(cx, mitem, item, push, false); @@ -483,72 +484,62 @@ impl<'a> TraitDef<'a> { self, cx: &ExtCtxt<'_>, mitem: &ast::MetaItem, - item: &'a Annotatable, + item: &'a ast::Item, push: &mut dyn FnMut(Annotatable), from_scratch: bool, ) { - match item { - Annotatable::Item(item) => { - let is_packed = matches!( - AttributeParser::parse_limited_sym(cx.sess, &item.attrs, &[sym::repr]), - Some(Attribute::Parsed(AttributeKind::Repr { reprs, .. })) if reprs.iter().any(|(x, _)| matches!(x, ReprPacked(..))) - ); + let is_packed = matches!( + AttributeParser::parse_limited_sym(cx.sess, &item.attrs, &[sym::repr]), + Some(Attribute::Parsed(AttributeKind::Repr { reprs, .. })) if reprs.iter().any(|(x, _)| matches!(x, ReprPacked(..))) + ); - let mut newitem = match &item.kind { - ast::ItemKind::Struct(ident, generics, struct_def) => self.expand_struct_def( + let mut newitem = match &item.kind { + ast::ItemKind::Struct(ident, generics, struct_def) => { + self.expand_struct_def(cx, struct_def, *ident, generics, from_scratch, is_packed) + } + ast::ItemKind::Enum(ident, generics, enum_def) => { + // We ignore `is_packed` here, because `repr(packed)` + // enums cause an error later on. + // + // This can only cause further compilation errors + // downstream in blatantly illegal code, so it is fine. + self.expand_enum_def(cx, enum_def, *ident, generics, from_scratch) + } + ast::ItemKind::Union(ident, generics, struct_def) => { + if self.supports_unions { + self.expand_struct_def( cx, struct_def, *ident, generics, from_scratch, is_packed, - ), - ast::ItemKind::Enum(ident, generics, enum_def) => { - // We ignore `is_packed` here, because `repr(packed)` - // enums cause an error later on. - // - // This can only cause further compilation errors - // downstream in blatantly illegal code, so it is fine. - self.expand_enum_def(cx, enum_def, *ident, generics, from_scratch) - } - ast::ItemKind::Union(ident, generics, struct_def) => { - if self.supports_unions { - self.expand_struct_def( - cx, - struct_def, - *ident, - generics, - from_scratch, - is_packed, - ) - } else { - cx.dcx().emit_err(diagnostics::DeriveUnion { span: mitem.span }); - return; - } - } - _ => unreachable!(), - }; - // Keep the lint attributes of the previous item to control how the - // generated implementations are linted - newitem.attrs.extend( - item.attrs - .iter() - .filter(|a| { - a.has_any_name(&[ - sym::allow, - sym::warn, - sym::deny, - sym::forbid, - sym::stable, - sym::unstable, - ]) - }) - .cloned(), - ); - push(Annotatable::Item(newitem)) + ) + } else { + cx.dcx().emit_err(diagnostics::DeriveUnion { span: mitem.span }); + return; + } } _ => unreachable!(), - } + }; + // Keep the lint attributes of the previous item to control how the + // generated implementations are linted + newitem.attrs.extend( + item.attrs + .iter() + .filter(|a| { + a.has_any_name(&[ + sym::allow, + sym::warn, + sym::deny, + sym::forbid, + sym::stable, + sym::unstable, + ]) + }) + .cloned(), + ); + push(Annotatable::Item(newitem)) } /// Given that we are deriving a trait `DerivedTrait` for a type like: diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index f1931aa90a435..5e32a12b6fdca 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -11,7 +11,7 @@ pub(crate) fn expand_deriving_hash( cx: &ExtCtxt<'_>, span: Span, mitem: &MetaItem, - item: &Annotatable, + item: &ast::Item, push: &mut dyn FnMut(Annotatable), is_const: bool, ) { diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index 602af919bd4f2..55838e09b304b 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -35,7 +35,7 @@ pub(crate) mod partial_ord; pub(crate) mod generic; pub(crate) type BuiltinDeriveFn = - fn(&ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable), bool); + fn(&ExtCtxt<'_>, Span, &MetaItem, &ast::Item, &mut dyn FnMut(Annotatable), bool); pub(crate) struct BuiltinDerive(pub(crate) BuiltinDeriveFn); @@ -59,7 +59,7 @@ impl MultiItemModifier for BuiltinDerive { ecx, span, meta_item, - &Annotatable::Item(item), + &item, &mut |a| { // Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx' // to the function @@ -75,9 +75,10 @@ impl MultiItemModifier for BuiltinDerive { unreachable!("should have already errored on non-item statement") } } - _ => { - (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a), is_derive_const); + Annotatable::Item(item) => { + (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a), is_derive_const) } + _ => unreachable!(), } ExpandResult::Ready(items) } diff --git a/compiler/rustc_builtin_macros/src/deriving/reborrow.rs b/compiler/rustc_builtin_macros/src/deriving/reborrow.rs index 9dc1ccf4fd8e6..c1b8dfb53c694 100644 --- a/compiler/rustc_builtin_macros/src/deriving/reborrow.rs +++ b/compiler/rustc_builtin_macros/src/deriving/reborrow.rs @@ -15,7 +15,7 @@ pub(crate) fn expand_deriving_reborrow( cx: &ExtCtxt<'_>, span: Span, _mitem: &MetaItem, - item: &Annotatable, + item: &ast::Item, push: &mut dyn FnMut(Annotatable), _is_const: bool, ) { @@ -30,7 +30,7 @@ pub(crate) fn expand_deriving_coerce_shared( cx: &ExtCtxt<'_>, span: Span, _mitem: &MetaItem, - item: &Annotatable, + item: &ast::Item, push: &mut dyn FnMut(Annotatable), _is_const: bool, ) { @@ -55,25 +55,19 @@ pub(crate) fn expand_deriving_coerce_shared( fn struct_def<'a>( cx: &ExtCtxt<'_>, span: Span, - item: &'a Annotatable, + item: &'a ast::Item, trait_name: Symbol, ) -> Option<(Ident, &'a Generics)> { - match item { - Annotatable::Item(item) => match &item.kind { - ItemKind::Struct(ident, generics, _) => Some((*ident, generics)), - ItemKind::Enum(..) => { - cx.dcx().emit_err(UnsupportedItem { span, trait_name, kind: "enum" }); - None - } - ItemKind::Union(..) => { - cx.dcx().emit_err(UnsupportedItem { span, trait_name, kind: "union" }); - None - } - _ => { - cx.dcx().emit_err(UnsupportedItem { span, trait_name, kind: "item" }); - None - } - }, + match &item.kind { + ItemKind::Struct(ident, generics, _) => Some((*ident, generics)), + ItemKind::Enum(..) => { + cx.dcx().emit_err(UnsupportedItem { span, trait_name, kind: "enum" }); + None + } + ItemKind::Union(..) => { + cx.dcx().emit_err(UnsupportedItem { span, trait_name, kind: "union" }); + None + } _ => { cx.dcx().emit_err(UnsupportedItem { span, trait_name, kind: "item" }); None @@ -81,12 +75,7 @@ fn struct_def<'a>( } } -fn coerce_shared_target(cx: &ExtCtxt<'_>, span: Span, item: &Annotatable) -> Option> { - let Annotatable::Item(item) = item else { - cx.dcx().emit_err(MissingTarget { span }); - return None; - }; - +fn coerce_shared_target(cx: &ExtCtxt<'_>, span: Span, item: &ast::Item) -> Option> { let mut attrs = item.attrs.iter().filter(|attr| attr.has_name(sym::coerce_shared)); let Some(attr) = attrs.next() else { cx.dcx().emit_err(MissingTarget { span }); From 12beb43c72bf426162dc9fb888ae17e8fb0617ea Mon Sep 17 00:00:00 2001 From: cyrgani Date: Mon, 24 Aug 2026 13:11:46 +0000 Subject: [PATCH 04/29] take `Box` instead of `Annotatable` as the `push` argument --- .../rustc_builtin_macros/src/deriving/bounds.rs | 6 +++--- .../rustc_builtin_macros/src/deriving/clone.rs | 4 ++-- .../rustc_builtin_macros/src/deriving/cmp/eq.rs | 4 ++-- .../rustc_builtin_macros/src/deriving/cmp/ord.rs | 4 ++-- .../src/deriving/cmp/partial_eq.rs | 4 ++-- .../src/deriving/cmp/partial_ord.rs | 4 ++-- .../src/deriving/coerce_pointee.rs | 10 +++++----- .../rustc_builtin_macros/src/deriving/debug.rs | 4 ++-- .../rustc_builtin_macros/src/deriving/default.rs | 4 ++-- .../rustc_builtin_macros/src/deriving/from.rs | 4 ++-- .../src/deriving/generic/mod.rs | 8 ++++---- .../rustc_builtin_macros/src/deriving/hash.rs | 4 ++-- compiler/rustc_builtin_macros/src/deriving/mod.rs | 15 ++++++++++----- .../rustc_builtin_macros/src/deriving/reborrow.rs | 12 ++++++------ 14 files changed, 46 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 5b71d38c63e2e..da5370e3e7819 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -1,5 +1,5 @@ use rustc_ast::{MetaItem, Safety}; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_span::Span; use crate::deriving::generic::*; @@ -10,7 +10,7 @@ pub(crate) fn expand_deriving_copy( span: Span, mitem: &MetaItem, item: &ast::Item, - push: &mut dyn FnMut(Annotatable), + push: &mut dyn FnMut(Box), is_const: bool, ) { let trait_def = TraitDef { @@ -35,7 +35,7 @@ pub(crate) fn expand_deriving_const_param_ty( span: Span, mitem: &MetaItem, item: &ast::Item, - push: &mut dyn FnMut(Annotatable), + push: &mut dyn FnMut(Box), is_const: bool, ) { let trait_def = TraitDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index be70cf0b584a1..f0c274bce5b58 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -1,6 +1,6 @@ use rustc_ast::{self as ast, Generics, ItemKind, MetaItem, Safety, VariantData}; use rustc_data_structures::fx::FxHashSet; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_span::{DUMMY_SP, Ident, Span, kw, sym}; use thin_vec::{ThinVec, thin_vec}; @@ -13,7 +13,7 @@ pub(crate) fn expand_deriving_clone( span: Span, mitem: &MetaItem, item: &ast::Item, - push: &mut dyn FnMut(Annotatable), + push: &mut dyn FnMut(Box), is_const: bool, ) { // The simple form is `fn clone(&self) -> Self { *self }`, possibly with diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 0df5767e2bde0..8c160cb9868bf 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -1,6 +1,6 @@ use rustc_ast::{self as ast, MetaItem, Safety}; use rustc_data_structures::fx::FxHashSet; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_span::{Span, sym}; use thin_vec::{ThinVec, thin_vec}; @@ -13,7 +13,7 @@ pub(crate) fn expand_deriving_eq( span: Span, mitem: &MetaItem, item: &ast::Item, - push: &mut dyn FnMut(Annotatable), + push: &mut dyn FnMut(Box), is_const: bool, ) { let span = cx.with_def_site_ctxt(span); diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index 84e5485020a1f..fb8d425841722 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -1,5 +1,5 @@ use rustc_ast::{MetaItem, Safety}; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_span::{Ident, Span, sym}; use thin_vec::thin_vec; @@ -12,7 +12,7 @@ pub(crate) fn expand_deriving_ord( span: Span, mitem: &MetaItem, item: &ast::Item, - push: &mut dyn FnMut(Annotatable), + push: &mut dyn FnMut(Box), is_const: bool, ) { let trait_def = TraitDef { diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index fb3d6e9b338f7..8c442f7dbaa5f 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -1,5 +1,5 @@ use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability, Safety}; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_span::{Span, sym}; use thin_vec::thin_vec; @@ -14,7 +14,7 @@ pub(crate) fn expand_deriving_partial_eq( span: Span, mitem: &MetaItem, item: &ast::Item, - push: &mut dyn FnMut(Annotatable), + push: &mut dyn FnMut(Box), is_const: bool, ) { let structural_trait_def = TraitDef { 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 8b778a014ade0..0e547d441a74b 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -1,5 +1,5 @@ use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind, Safety, ast}; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_span::{Ident, Span, sym}; use thin_vec::thin_vec; @@ -12,7 +12,7 @@ pub(crate) fn expand_deriving_partial_ord( span: Span, mitem: &MetaItem, item: &ast::Item, - push: &mut dyn FnMut(Annotatable), + push: &mut dyn FnMut(Box), is_const: bool, ) { let ordering_ty = Path(path_std!(cmp::Ordering)); diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index a18af8e035c68..58b4734b132c3 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -7,7 +7,7 @@ use rustc_ast::{ }; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_errors::E0802; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_macros::Diagnostic; use rustc_span::{Ident, Span, Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; @@ -23,7 +23,7 @@ pub(crate) fn expand_deriving_coerce_pointee( span: Span, _mitem: &MetaItem, item: &ast::Item, - push: &mut dyn FnMut(Annotatable), + push: &mut dyn FnMut(Box), _is_const: bool, ) { DetectNonGenericPointeeAttr { cx }.visit_item(item); @@ -102,7 +102,7 @@ pub(crate) fn expand_deriving_coerce_pointee( let trait_path = cx.path_all(span, true, path!(span, core::marker::CoercePointeeValidated), vec![]); let trait_ref = cx.trait_ref(trait_path); - push(Annotatable::Item( + push( cx.item( span, attrs.clone(), @@ -142,7 +142,7 @@ pub(crate) fn expand_deriving_coerce_pointee( items: ThinVec::new(), }), ), - )); + ); } let mut add_impl_block = |generics, trait_symbol, trait_args| { let mut parts = path!(span, core::ops); @@ -165,7 +165,7 @@ pub(crate) fn expand_deriving_coerce_pointee( items: ThinVec::new(), }), ); - push(Annotatable::Item(item)); + push(item); }; // Create unsized `self`, that is, one where the `#[pointee]` type arg is replaced with `__S`. For diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 74dd639298d1c..3c80c01aa32b0 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -1,5 +1,5 @@ use rustc_ast::{self as ast, EnumDef, MetaItem, Safety}; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_session::config::FmtDebug; use rustc_span::{Ident, Span, Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; @@ -13,7 +13,7 @@ pub(crate) fn expand_deriving_debug( span: Span, mitem: &MetaItem, item: &ast::Item, - push: &mut dyn FnMut(Annotatable), + push: &mut dyn FnMut(Box), is_const: bool, ) { // &mut ::std::fmt::Formatter diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 4293c89d15f96..88e9d8daf1bd9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -2,7 +2,7 @@ use core::ops::ControlFlow; use rustc_ast::visit::{Visitor, visit_opt}; use rustc_ast::{self as ast, EnumDef, Safety, VariantData, attr}; -use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; +use rustc_expand::base::{DummyResult, ExtCtxt}; use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym}; use smallvec::SmallVec; use thin_vec::{ThinVec, thin_vec}; @@ -16,7 +16,7 @@ pub(crate) fn expand_deriving_default( span: Span, mitem: &ast::MetaItem, item: &ast::Item, - push: &mut dyn FnMut(Annotatable), + push: &mut dyn FnMut(Box), is_const: bool, ) { DetectNonVariantDefaultAttr { cx }.visit_item(item); diff --git a/compiler/rustc_builtin_macros/src/deriving/from.rs b/compiler/rustc_builtin_macros/src/deriving/from.rs index 4f7d7fe15b616..ab5008f90ff00 100644 --- a/compiler/rustc_builtin_macros/src/deriving/from.rs +++ b/compiler/rustc_builtin_macros/src/deriving/from.rs @@ -1,7 +1,7 @@ use rustc_ast as ast; use rustc_ast::{ItemKind, Safety, VariantData}; use rustc_errors::MultiSpan; -use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; +use rustc_expand::base::{DummyResult, ExtCtxt}; use rustc_span::{Ident, Span, kw, sym}; use thin_vec::thin_vec; @@ -17,7 +17,7 @@ pub(crate) fn expand_deriving_from( span: Span, mitem: &ast::MetaItem, item: &ast::Item, - push: &mut dyn FnMut(Annotatable), + push: &mut dyn FnMut(Box), is_const: bool, ) { let err_span = || { diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index cfd336fafc4a9..436881dbf2209 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -188,7 +188,7 @@ use rustc_ast::{ }; use rustc_attr_ir::{Attribute, AttributeKind, ReprPacked}; use rustc_attr_parsing::AttributeParser; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, respan, sym}; pub(crate) use smallvec::{SmallVec, smallvec}; use thin_vec::{ThinVec, thin_vec}; @@ -475,7 +475,7 @@ impl<'a> TraitDef<'a> { cx: &ExtCtxt<'_>, mitem: &ast::MetaItem, item: &'a ast::Item, - push: &mut dyn FnMut(Annotatable), + push: &mut dyn FnMut(Box), ) { self.expand_ext(cx, mitem, item, push, false); } @@ -485,7 +485,7 @@ impl<'a> TraitDef<'a> { cx: &ExtCtxt<'_>, mitem: &ast::MetaItem, item: &'a ast::Item, - push: &mut dyn FnMut(Annotatable), + push: &mut dyn FnMut(Box), from_scratch: bool, ) { let is_packed = matches!( @@ -539,7 +539,7 @@ impl<'a> TraitDef<'a> { }) .cloned(), ); - push(Annotatable::Item(newitem)) + push(newitem); } /// Given that we are deriving a trait `DerivedTrait` for a type like: diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index 5e32a12b6fdca..6864b05ae08cd 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -1,5 +1,5 @@ use rustc_ast::{MetaItem, Mutability, Safety}; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_span::{Span, sym}; use thin_vec::thin_vec; @@ -12,7 +12,7 @@ pub(crate) fn expand_deriving_hash( span: Span, mitem: &MetaItem, item: &ast::Item, - push: &mut dyn FnMut(Annotatable), + push: &mut dyn FnMut(Box), is_const: bool, ) { let path = path_std!(hash::Hash); diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index 55838e09b304b..7c010f62bfd15 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -35,7 +35,7 @@ pub(crate) mod partial_ord; pub(crate) mod generic; pub(crate) type BuiltinDeriveFn = - fn(&ExtCtxt<'_>, Span, &MetaItem, &ast::Item, &mut dyn FnMut(Annotatable), bool); + fn(&ExtCtxt<'_>, Span, &MetaItem, &ast::Item, &mut dyn FnMut(Box), bool); pub(crate) struct BuiltinDerive(pub(crate) BuiltinDeriveFn); @@ -65,7 +65,7 @@ impl MultiItemModifier for BuiltinDerive { // to the function items.push(Annotatable::Stmt(Box::new(ast::Stmt { id: ast::DUMMY_NODE_ID, - kind: ast::StmtKind::Item(a.expect_item()), + kind: ast::StmtKind::Item(a), span, }))); }, @@ -75,9 +75,14 @@ impl MultiItemModifier for BuiltinDerive { unreachable!("should have already errored on non-item statement") } } - Annotatable::Item(item) => { - (self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a), is_derive_const) - } + Annotatable::Item(item) => (self.0)( + ecx, + span, + meta_item, + &item, + &mut |a| items.push(Annotatable::Item(a)), + is_derive_const, + ), _ => unreachable!(), } ExpandResult::Ready(items) diff --git a/compiler/rustc_builtin_macros/src/deriving/reborrow.rs b/compiler/rustc_builtin_macros/src/deriving/reborrow.rs index c1b8dfb53c694..43d24417acc00 100644 --- a/compiler/rustc_builtin_macros/src/deriving/reborrow.rs +++ b/compiler/rustc_builtin_macros/src/deriving/reborrow.rs @@ -2,7 +2,7 @@ use rustc_ast::{ self as ast, AttrArgs, GenericArg, GenericParamKind, Generics, ItemKind, MetaItem, token, }; use rustc_errors::E0802; -use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_expand::base::ExtCtxt; use rustc_macros::Diagnostic; use rustc_span::{Ident, Span, Symbol, sym}; use thin_vec::ThinVec; @@ -16,7 +16,7 @@ pub(crate) fn expand_deriving_reborrow( span: Span, _mitem: &MetaItem, item: &ast::Item, - push: &mut dyn FnMut(Annotatable), + push: &mut dyn FnMut(Box), _is_const: bool, ) { let Some((ident, generics)) = struct_def(cx, span, item, sym::Reborrow) else { @@ -31,7 +31,7 @@ pub(crate) fn expand_deriving_coerce_shared( span: Span, _mitem: &MetaItem, item: &ast::Item, - push: &mut dyn FnMut(Annotatable), + push: &mut dyn FnMut(Box), _is_const: bool, ) { let Some((ident, generics)) = struct_def(cx, span, item, sym::CoerceShared) else { @@ -119,7 +119,7 @@ fn push_marker_impl( generics: &Generics, trait_name: Symbol, trait_args: Vec, - push: &mut dyn FnMut(Annotatable), + push: &mut dyn FnMut(Box), ) { let mut trait_parts = path!(span, core::marker); trait_parts.push(Ident::new(trait_name, span)); @@ -143,7 +143,7 @@ fn push_marker_impl( .collect(); let self_ty = cx.ty_path(cx.path_all(span, false, vec![ident], self_params)); - push(Annotatable::Item(cx.item( + push(cx.item( span, thin_vec::thin_vec![cx.attr_word(sym::automatically_derived, span)], ast::ItemKind::Impl(ast::Impl { @@ -158,7 +158,7 @@ fn push_marker_impl( self_ty, items: ThinVec::new(), }), - ))); + )); } fn impl_generics(cx: &ExtCtxt<'_>, generics: &Generics) -> Generics { From 6221469c4f435c98dcce2341d95f081e39592b57 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Wed, 26 Aug 2026 11:24:54 +0000 Subject: [PATCH 05/29] several small cleanups --- .../src/deriving/cmp/partial_eq.rs | 12 +++++------- compiler/rustc_builtin_macros/src/deriving/from.rs | 2 +- compiler/rustc_builtin_macros/src/deriving/mod.rs | 10 +--------- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 8c442f7dbaa5f..a65962bfc9731 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -47,9 +47,7 @@ pub(crate) fn expand_deriving_partial_eq( ret_ty: Path(generic::ty::Path::new_local(sym::bool)), attributes: thin_vec![cx.attr_word(sym::inline, span)], fieldless_variants_strategy: FieldlessVariantsStrategy::Unify, - combine_substructure: combine_substructure(|a, b, c| { - BlockOrExpr::new_expr(get_substructure_equality_expr(a, b, c)) - }), + combine_substructure: combine_substructure(get_substructure_equality_expr), }]; let trait_def = TraitDef { @@ -123,10 +121,10 @@ fn get_substructure_equality_expr( cx: &ExtCtxt<'_>, span: Span, substructure: &Substructure<'_>, -) -> Box { +) -> BlockOrExpr { use SubstructureFields::*; - match substructure.fields { + BlockOrExpr::new_expr(match substructure.fields { EnumMatching(.., fields) | Struct(.., fields) => { let combine = move |acc, field| { let rhs = get_field_equality_expr(cx, field); @@ -151,7 +149,7 @@ fn get_substructure_equality_expr( EnumDiscr(disc, match_expr) => { let lhs = get_field_equality_expr(cx, disc); let Some(match_expr) = match_expr else { - return lhs; + return BlockOrExpr::new_expr(lhs); }; // Compare the discriminant first (cheaper), then the rest of the // fields. @@ -169,7 +167,7 @@ fn get_substructure_equality_expr( span, "unexpected all-fieldless enum encountered during `derive(PartialEq)` expansion", ), - } + }) } /// Generates an equality comparison expression for a single struct or enum diff --git a/compiler/rustc_builtin_macros/src/deriving/from.rs b/compiler/rustc_builtin_macros/src/deriving/from.rs index ab5008f90ff00..0758ff0269a96 100644 --- a/compiler/rustc_builtin_macros/src/deriving/from.rs +++ b/compiler/rustc_builtin_macros/src/deriving/from.rs @@ -75,7 +75,7 @@ pub(crate) fn expand_deriving_from( supports_unions: false, methods: smallvec![MethodDef { name: sym::from, - generics: Bounds { bounds: vec![] }, + generics: Bounds::empty(), explicit_self: false, nonself_args: smallvec![(from_type, sym::value)], ret_ty: Ty::Self_, diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index 7c010f62bfd15..75bd98893de80 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -60,15 +60,7 @@ impl MultiItemModifier for BuiltinDerive { span, meta_item, &item, - &mut |a| { - // Cannot use 'ecx.stmt_item' here, because we need to pass 'ecx' - // to the function - items.push(Annotatable::Stmt(Box::new(ast::Stmt { - id: ast::DUMMY_NODE_ID, - kind: ast::StmtKind::Item(a), - span, - }))); - }, + &mut |a| items.push(Annotatable::Stmt(Box::new(ecx.stmt_item(span, a)))), is_derive_const, ); } else { From a054d6fa5792d4c4bfb9af4a019447b8d19648fd Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 27 Aug 2026 10:02:57 +0000 Subject: [PATCH 06/29] remove one use of `expand_ext` --- compiler/rustc_builtin_macros/src/deriving/clone.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index f0c274bce5b58..f072b4b9e5cd1 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -77,7 +77,7 @@ pub(crate) fn expand_deriving_clone( document: false, }; - trivial_def.expand_ext(cx, mitem, item, push, true); + trivial_def.expand(cx, mitem, item, push); } let trait_def = TraitDef { From 2bc7a8762f91d4bf92b5b7c07465aa9fd43182c5 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 27 Aug 2026 11:54:24 +0000 Subject: [PATCH 07/29] dissolve the `cmp` subdirectory --- .../rustc_builtin_macros/src/deriving/{cmp => }/eq.rs | 0 compiler/rustc_builtin_macros/src/deriving/mod.rs | 9 ++------- .../rustc_builtin_macros/src/deriving/{cmp => }/ord.rs | 0 .../src/deriving/{cmp => }/partial_eq.rs | 0 .../src/deriving/{cmp => }/partial_ord.rs | 0 5 files changed, 2 insertions(+), 7 deletions(-) rename compiler/rustc_builtin_macros/src/deriving/{cmp => }/eq.rs (100%) rename compiler/rustc_builtin_macros/src/deriving/{cmp => }/ord.rs (100%) rename compiler/rustc_builtin_macros/src/deriving/{cmp => }/partial_eq.rs (100%) rename compiler/rustc_builtin_macros/src/deriving/{cmp => }/partial_ord.rs (100%) diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/eq.rs similarity index 100% rename from compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs rename to compiler/rustc_builtin_macros/src/deriving/eq.rs diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index 75bd98893de80..337ee43938bd7 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -19,18 +19,13 @@ pub(crate) mod clone; pub(crate) mod coerce_pointee; pub(crate) mod debug; pub(crate) mod default; +pub(crate) mod eq; pub(crate) mod from; pub(crate) mod hash; -pub(crate) mod reborrow; - -#[path = "cmp/eq.rs"] -pub(crate) mod eq; -#[path = "cmp/ord.rs"] pub(crate) mod ord; -#[path = "cmp/partial_eq.rs"] pub(crate) mod partial_eq; -#[path = "cmp/partial_ord.rs"] pub(crate) mod partial_ord; +pub(crate) mod reborrow; pub(crate) mod generic; diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/ord.rs similarity index 100% rename from compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs rename to compiler/rustc_builtin_macros/src/deriving/ord.rs diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/partial_eq.rs similarity index 100% rename from compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs rename to compiler/rustc_builtin_macros/src/deriving/partial_eq.rs diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/partial_ord.rs similarity index 100% rename from compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs rename to compiler/rustc_builtin_macros/src/deriving/partial_ord.rs From c1867744a9c12aa6f97777be4f9d3d404f8be334 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 27 Aug 2026 12:00:20 +0000 Subject: [PATCH 08/29] split `bounds` module into `const_param_ty` and `copy` modules --- .../deriving/{bounds.rs => const_param_ty.rs} | 25 --------------- .../rustc_builtin_macros/src/deriving/copy.rs | 31 +++++++++++++++++++ .../rustc_builtin_macros/src/deriving/mod.rs | 3 +- compiler/rustc_builtin_macros/src/lib.rs | 4 +-- 4 files changed, 35 insertions(+), 28 deletions(-) rename compiler/rustc_builtin_macros/src/deriving/{bounds.rs => const_param_ty.rs} (56%) create mode 100644 compiler/rustc_builtin_macros/src/deriving/copy.rs diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/const_param_ty.rs similarity index 56% rename from compiler/rustc_builtin_macros/src/deriving/bounds.rs rename to compiler/rustc_builtin_macros/src/deriving/const_param_ty.rs index da5370e3e7819..18a9df86b547e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/const_param_ty.rs @@ -5,31 +5,6 @@ use rustc_span::Span; use crate::deriving::generic::*; use crate::deriving::path_std; -pub(crate) fn expand_deriving_copy( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &ast::Item, - push: &mut dyn FnMut(Box), - is_const: bool, -) { - let trait_def = TraitDef { - span, - path: path_std!(marker::Copy), - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: false, - additional_bounds: SmallVec::new(), - supports_unions: true, - methods: SmallVec::new(), - associated_types: SmallVec::new(), - is_const, - safety: Safety::Default, - document: true, - }; - - trait_def.expand(cx, mitem, item, push); -} - pub(crate) fn expand_deriving_const_param_ty( cx: &ExtCtxt<'_>, span: Span, diff --git a/compiler/rustc_builtin_macros/src/deriving/copy.rs b/compiler/rustc_builtin_macros/src/deriving/copy.rs new file mode 100644 index 0000000000000..5743d27cf7458 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/deriving/copy.rs @@ -0,0 +1,31 @@ +use rustc_ast::{MetaItem, Safety}; +use rustc_expand::base::ExtCtxt; +use rustc_span::Span; + +use crate::deriving::generic::*; +use crate::deriving::path_std; + +pub(crate) fn expand_deriving_copy( + cx: &ExtCtxt<'_>, + span: Span, + mitem: &MetaItem, + item: &ast::Item, + push: &mut dyn FnMut(Box), + is_const: bool, +) { + let trait_def = TraitDef { + span, + path: path_std!(marker::Copy), + skip_path_as_bound: false, + needs_copy_as_bound_if_packed: false, + additional_bounds: SmallVec::new(), + supports_unions: true, + methods: SmallVec::new(), + associated_types: SmallVec::new(), + is_const, + safety: Safety::Default, + document: true, + }; + + trait_def.expand(cx, mitem, item, push); +} diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index 337ee43938bd7..404991903c424 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -14,9 +14,10 @@ macro path_std($($x:tt)*) { generic::ty::Path::new( pathvec!( $($x)* ) ) } -pub(crate) mod bounds; pub(crate) mod clone; pub(crate) mod coerce_pointee; +pub(crate) mod const_param_ty; +pub(crate) mod copy; pub(crate) mod debug; pub(crate) mod default; pub(crate) mod eq; diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index db92413e1b162..57759bb113401 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -133,8 +133,8 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { register_derive! { Clone: clone::expand_deriving_clone, CoerceShared: reborrow::expand_deriving_coerce_shared, - Copy: bounds::expand_deriving_copy, - ConstParamTy: bounds::expand_deriving_const_param_ty, + Copy: copy::expand_deriving_copy, + ConstParamTy: const_param_ty::expand_deriving_const_param_ty, Debug: debug::expand_deriving_debug, Default: default::expand_deriving_default, Eq: eq::expand_deriving_eq, From 38adf7bdccddf56a557dc141990f748a7701d68a Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 27 Aug 2026 12:35:28 +0000 Subject: [PATCH 09/29] remove last `StaticFields` usage --- .../src/deriving/default.rs | 40 +++++++++++-------- tests/ui/derives/deriving-all-codegen.stdout | 2 +- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 88e9d8daf1bd9..eb9a302be31e0 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -38,8 +38,8 @@ pub(crate) fn expand_deriving_default( fieldless_variants_strategy: FieldlessVariantsStrategy::Default, combine_substructure: combine_substructure(|cx, trait_span, substr| { match substr.fields { - StaticStruct(_, fields) => { - default_struct_substructure(cx, trait_span, substr, fields) + StaticStruct(variant_data, _) => { + default_struct_substructure(cx, trait_span, substr, variant_data) } StaticEnum(enum_def) => { default_enum_substructure(cx, trait_span, enum_def, item.span) @@ -66,27 +66,35 @@ fn default_struct_substructure( cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>, - summary: &StaticFields<'_>, + variant_data: &VariantData, ) -> BlockOrExpr { - let expr = match summary { - Unnamed(_, IsTuple::No) => cx.expr_ident(trait_span, substr.type_ident), - Unnamed(fields, IsTuple::Yes) => { - let exprs = fields.iter().map(|sp| default_call(cx, *sp)).collect(); + let expr = match variant_data { + VariantData::Unit(_) => cx.expr_ident(trait_span, substr.type_ident), + VariantData::Tuple(fields, _) => { + let exprs = fields + .iter() + .map(|field| default_call(cx, field.span.with_ctxt(trait_span.ctxt()))) + .collect(); cx.expr_call_ident(trait_span, substr.type_ident, exprs) } - Named(fields) => { + VariantData::Struct { fields, .. } => { let default_fields = fields .iter() - .map(|&(ident, span, default_val)| { - let value = match default_val { - // We use `Default::default()`. - None => default_call(cx, span), + .map(|field| { + let span = field.span.with_ctxt(trait_span.ctxt()); + let value = if let Some(extras) = &field.extras + && let Some(default_val) = &extras.default + { // We use the field default const expression. - Some(val) => { - cx.expr(val.value.span, ast::ExprKind::ConstBlock(val.clone())) - } + cx.expr( + default_val.value.span, + ast::ExprKind::ConstBlock(default_val.clone()), + ) + } else { + // We use `Default::default()`. + default_call(cx, span) }; - cx.field_imm(span, ident, value) + cx.field_imm(span, field.ident.unwrap(), value) }) .collect(); cx.expr_struct_ident(trait_span, substr.type_ident, default_fields) diff --git a/tests/ui/derives/deriving-all-codegen.stdout b/tests/ui/derives/deriving-all-codegen.stdout index 320c1b5861162..54b1976207236 100644 --- a/tests/ui/derives/deriving-all-codegen.stdout +++ b/tests/ui/derives/deriving-all-codegen.stdout @@ -46,7 +46,7 @@ impl ::core::fmt::Debug for Empty { #[automatically_derived] impl ::core::default::Default for Empty { #[inline] - fn default() -> Empty { Empty {} } + fn default() -> Empty { Empty } } #[automatically_derived] impl ::core::hash::Hash for Empty { From 3c3c3cdcc75ecd82ef68fc63721cd53aa43b3531 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Thu, 27 Aug 2026 12:39:06 +0000 Subject: [PATCH 10/29] remove `StaticFields` and `IsTuple` --- .../src/deriving/default.rs | 2 +- .../rustc_builtin_macros/src/deriving/from.rs | 2 +- .../src/deriving/generic/mod.rs | 72 ++----------------- 3 files changed, 7 insertions(+), 69 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index eb9a302be31e0..9e65ae0b75cab 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -38,7 +38,7 @@ pub(crate) fn expand_deriving_default( fieldless_variants_strategy: FieldlessVariantsStrategy::Default, combine_substructure: combine_substructure(|cx, trait_span, substr| { match substr.fields { - StaticStruct(variant_data, _) => { + StaticStruct(variant_data) => { default_struct_substructure(cx, trait_span, substr, variant_data) } StaticEnum(enum_def) => { diff --git a/compiler/rustc_builtin_macros/src/deriving/from.rs b/compiler/rustc_builtin_macros/src/deriving/from.rs index 0758ff0269a96..eb8ddd10d4306 100644 --- a/compiler/rustc_builtin_macros/src/deriving/from.rs +++ b/compiler/rustc_builtin_macros/src/deriving/from.rs @@ -91,7 +91,7 @@ pub(crate) fn expand_deriving_from( let self_kw = Ident::new(kw::SelfUpper, span); let expr: Box = match substructure.fields { - SubstructureFields::StaticStruct(variant, _) => match variant { + SubstructureFields::StaticStruct(variant) => match variant { // Self { field: value } VariantData::Struct { .. } => cx.expr_struct_ident( span, diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 436881dbf2209..3298b4a583ff8 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -177,14 +177,13 @@ use std::ops::Not; use std::{iter, vec}; -pub(crate) use StaticFields::*; pub(crate) use SubstructureFields::*; pub(crate) use rustc_ast as ast; use rustc_ast::token::{IdentIsRaw, LitKind, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenTree}; use rustc_ast::{ - AnonConst, AttrArgs, BindingMode, ByRef, DelimArgs, EnumDef, Expr, GenericArg, - GenericParamKind, Generics, Mutability, PatKind, Safety, SelfKind, VariantData, + AttrArgs, BindingMode, ByRef, DelimArgs, EnumDef, Expr, GenericArg, GenericParamKind, Generics, + Mutability, PatKind, Safety, SelfKind, VariantData, }; use rustc_attr_ir::{Attribute, AttributeKind, ReprPacked}; use rustc_attr_parsing::AttributeParser; @@ -294,20 +293,6 @@ pub(crate) struct FieldInfo { pub maybe_scalar: bool, } -#[derive(Copy, Clone)] -pub(crate) enum IsTuple { - No, - Yes, -} - -/// Fields for a static method -pub(crate) enum StaticFields<'a> { - /// Tuple and unit structs/enum variants like this. - Unnamed(Vec, IsTuple), - /// Normal structs/struct variants. - Named(Vec<(Ident, Span, Option<&'a AnonConst>)>), -} - /// A summary of the possible sets of fields. pub(crate) enum SubstructureFields<'a> { /// A non-static method where `Self` is a struct. @@ -329,7 +314,7 @@ pub(crate) enum SubstructureFields<'a> { EnumDiscr(FieldInfo, Option>), /// A static method where `Self` is a struct. - StaticStruct(&'a ast::VariantData, StaticFields<'a>), + StaticStruct(&'a ast::VariantData), /// A static method where `Self` is an enum. StaticEnum(&'a ast::EnumDef), @@ -860,12 +845,12 @@ impl<'a> TraitDef<'a> { method_def.extract_arg_details(cx, self, type_ident, generics); let body = if from_scratch || method_def.is_static() { - method_def.expand_static_struct_method_body( + method_def.call_substructure_method( cx, self, - struct_def, type_ident, &nonselflike_args, + &StaticStruct(struct_def), ) } else { method_def.expand_struct_method_body( @@ -1133,25 +1118,6 @@ impl<'a> MethodDef<'a> { ) } - fn expand_static_struct_method_body( - &self, - cx: &ExtCtxt<'_>, - trait_: &TraitDef<'a>, - struct_def: &'a VariantData, - type_ident: Ident, - nonselflike_args: &[Box], - ) -> BlockOrExpr { - let summary = trait_.summarise_struct(cx, struct_def); - - self.call_substructure_method( - cx, - trait_, - type_ident, - nonselflike_args, - &StaticStruct(struct_def, summary), - ) - } - /// ``` /// #[derive(PartialEq)] /// # struct Dummy; @@ -1450,34 +1416,6 @@ impl<'a> MethodDef<'a> { // general helper methods. impl<'a> TraitDef<'a> { - fn summarise_struct(&self, cx: &ExtCtxt<'_>, struct_def: &'a VariantData) -> StaticFields<'a> { - let mut named_idents = Vec::new(); - let mut just_spans = Vec::new(); - for field in struct_def.fields() { - let sp = field.span.with_ctxt(self.span.ctxt()); - match field.ident { - Some(ident) => named_idents.push((ident, sp, field.default_value())), - _ => just_spans.push(sp), - } - } - - let is_tuple = match struct_def { - ast::VariantData::Tuple(..) => IsTuple::Yes, - _ => IsTuple::No, - }; - match (just_spans.is_empty(), named_idents.is_empty()) { - (false, false) => cx - .dcx() - .span_bug(self.span, "a struct with named and unnamed fields in generic `derive`"), - // named fields - (_, false) => Named(named_idents), - // unnamed fields - (false, _) => Unnamed(just_spans, is_tuple), - // empty - _ => Named(Vec::new()), - } - } - fn create_struct_patterns( &self, cx: &ExtCtxt<'_>, From 5f0a64e139d81c94304ce3df304f94704069c7d2 Mon Sep 17 00:00:00 2001 From: Obei Sideg Date: Fri, 21 Aug 2026 22:11:56 +0300 Subject: [PATCH 11/29] Use attribute parser for `#[non_exhaustive]` attribute check --- compiler/rustc_ast_lowering/src/expr.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 1 + compiler/rustc_ast_lowering/src/lib.rs | 7 +++-- .../src/attributes/non_exhaustive.rs | 28 +++++++++++++---- compiler/rustc_attr_parsing/src/context.rs | 4 +++ .../rustc_attr_parsing/src/diagnostics.rs | 9 ++++++ compiler/rustc_attr_parsing/src/interface.rs | 3 ++ compiler/rustc_passes/src/check_attr.rs | 30 +------------------ compiler/rustc_passes/src/diagnostics.rs | 9 ------ compiler/rustc_resolve/src/def_collector.rs | 1 + 10 files changed, 47 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 0a4a2ae7145e3..27ad70958db3e 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -175,7 +175,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let old_attrs = self.curr_owner.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]); let new_attrs = self - .lower_attrs_vec(&e.attrs, e.span, ex.hir_id, Target::from_expr(e)) + .lower_attrs_vec(&e.attrs, e.span, ex.hir_id, Target::from_expr(e), None) .into_iter() .chain(old_attrs.iter().cloned()); let new_attrs = &*self.arena.alloc_from_iter(new_attrs); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index b5e28d21a2613..256da9d6c7d5b 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -215,6 +215,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_ast_item(i), + Some(i), &extra_hir_attributes, ); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ef6995d9c11d6..2efcd250973a2 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1174,7 +1174,7 @@ impl<'hir> LoweringContext<'_, 'hir> { target_span: Span, target: Target, ) -> &'hir [hir::Attribute] { - self.lower_attrs_with_extra(id, attrs, target_span, target, &[]) + self.lower_attrs_with_extra(id, attrs, target_span, target, None, &[]) } fn lower_attrs_with_extra( @@ -1183,13 +1183,14 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, + target_item: Option<&ast::Item>, extra_hir_attributes: &[hir::Attribute], ) -> &'hir [hir::Attribute] { if attrs.is_empty() && extra_hir_attributes.is_empty() { &[] } else { let mut lowered_attrs = - self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target); + self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target, target_item); lowered_attrs.extend(extra_hir_attributes.iter().cloned()); assert_eq!(id.owner, self.curr_owner.owner_id); @@ -1216,12 +1217,14 @@ impl<'hir> LoweringContext<'_, 'hir> { target_span: Span, target_hir_id: HirId, target: Target, + target_item: Option<&ast::Item>, ) -> Vec { let l = self.span_lowerer(); self.attribute_parser.parse_attribute_list( attrs, target_span, target, + target_item, |s| l.lower(s), |lint_id, span, kind| { self.curr_owner.delayed_lints.push(DelayedLint { diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 48e97784a2286..30fdadf95e4ce 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -1,11 +1,8 @@ -use rustc_attr_ir::AttributeKind; -use rustc_attr_ir::target::Target; +use rustc_ast::{ItemKind, VariantData}; use rustc_feature::AttributeStability; -use rustc_span::{Span, Symbol, sym}; -use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; -use crate::target_checking::AllowedTargets; -use crate::target_checking::Policy::{Allow, Warn}; +use super::prelude::*; +use crate::diagnostics::NonExhaustiveWithDefaultFieldValues; pub(crate) struct NonExhaustiveParser; @@ -23,4 +20,23 @@ impl NoArgsAttributeParser for NonExhaustiveParser { ]); const STABILITY: AttributeStability = AttributeStability::Stable; const CREATE: fn(Span) -> AttributeKind = AttributeKind::NonExhaustive; + + fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) { + if cx.target != Target::Struct { + return; + } + + let item = cx.target_item.expect("missing AST target item for Target::Struct"); + let ItemKind::Struct(_, _, data) = &item.kind else { + panic!("expected struct AST target item for Target::Struct"); + }; + if let VariantData::Struct { fields, .. } = data + && fields.iter().any(|f| f.default_value().is_some()) + { + cx.emit_err(NonExhaustiveWithDefaultFieldValues { + attr_span, + defn_span: cx.target_span, + }); + } + } } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index cf99311cc0cfc..8d03c441acf16 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -833,6 +833,10 @@ pub(crate) struct FinalizeCheckContext<'p, 'sess> { /// /// Unlike [`all_attrs`](Self::all_attrs), this contains the fully parsed attributes. pub(crate) parsed_attrs: &'p [Attribute], + + /// The AST item these attributes were applied to, when the target is an item. + /// Used by `finalize_check` to inspect item structure that is not encoded in [`Target`]. + pub(crate) target_item: Option<&'p rustc_ast::ast::Item>, } impl<'p, 'sess: 'p> Deref for FinalizeCheckContext<'p, 'sess> { diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index 663915e39dccd..aeaada0e61409 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -1169,6 +1169,15 @@ pub(crate) struct DeprecatedAnnotationHasNoEffect { pub span: Span, } +#[derive(Diagnostic)] +#[diag("`#[non_exhaustive]` can't be used to annotate items with default field values")] +pub(crate) struct NonExhaustiveWithDefaultFieldValues { + #[primary_span] + pub attr_span: Span, + #[label("this struct has default field values")] + pub defn_span: Span, +} + #[derive(Diagnostic)] #[diag("expected single version literal")] pub(crate) struct ExpectedSingleVersionLiteral { diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 240f437828259..1cecce8fd43ef 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -161,6 +161,7 @@ impl<'sess> AttributeParser<'sess> { attrs, target_span, target, + None, std::convert::identity, |lint_id, span, kind| { sess.psess.dyn_buffer_lint_sess(lint_id.lint, span, target_node_id, kind.0) @@ -315,6 +316,7 @@ impl<'sess> AttributeParser<'sess> { attrs: &[ast::Attribute], target_span: Span, target: Target, + target_item: Option<&ast::Item>, lower_span: impl Copy + Fn(Span) -> Span, mut emit_lint: impl FnMut(LintId, MultiSpan, EmitAttribute), ) -> Vec { @@ -521,6 +523,7 @@ impl<'sess> AttributeParser<'sess> { }, all_attrs: &attr_paths, parsed_attrs: &attributes, + target_item, }, attr_span, ); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index cd7f422fb72f3..7da24f5251239 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -208,9 +208,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_rustc_allow_const_fn_unstable(hir_id, *first_span, span, target) } AttributeKind::Naked(..) => self.check_naked(hir_id, target), - AttributeKind::NonExhaustive(attr_span) => { - self.check_non_exhaustive(*attr_span, span, target, item) - } AttributeKind::MayDangle(attr_span) => self.check_may_dangle(hir_id, *attr_span), AttributeKind::Link(_, attr_span) => self.check_link(hir_id, *attr_span, target), AttributeKind::MacroExport { span, .. } => { @@ -293,6 +290,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::NoMain => (), AttributeKind::NoMangle(..) => (), AttributeKind::NoStd { .. } => (), + AttributeKind::NonExhaustive(_) => (), AttributeKind::OnUnknown { .. } => (), AttributeKind::OnUnmatchedArgs { .. } => (), AttributeKind::Opaque => (), @@ -797,32 +795,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. - fn check_non_exhaustive( - &self, - attr_span: Span, - span: Span, - target: Target, - item: Option<&'tcx Item<'tcx>>, - ) { - match target { - Target::Struct => { - if let hir::Item { - kind: hir::ItemKind::Struct(_, _, hir::VariantData::Struct { fields, .. }), - .. - } = item.unwrap() - && fields.iter().any(|f| f.default.is_some()) - { - self.dcx().emit_err(diagnostics::NonExhaustiveWithDefaultFieldValues { - attr_span, - defn_span: span, - }); - } - } - _ => {} - } - } - fn check_doc_alias_value(&self, span: Span, hir_id: HirId, target: Target, alias: Symbol) { if let Some(location) = match target { Target::AssocTy(_) => { diff --git a/compiler/rustc_passes/src/diagnostics.rs b/compiler/rustc_passes/src/diagnostics.rs index 5f99c4b133597..8b0ba0ab8f102 100644 --- a/compiler/rustc_passes/src/diagnostics.rs +++ b/compiler/rustc_passes/src/diagnostics.rs @@ -48,15 +48,6 @@ pub(crate) struct OuterCrateLevelAttrSuggestion { #[diag("crate-level attribute should be in the root module")] pub(crate) struct InnerCrateLevelAttr; -#[derive(Diagnostic)] -#[diag("`#[non_exhaustive]` can't be used to annotate items with default field values")] -pub(crate) struct NonExhaustiveWithDefaultFieldValues { - #[primary_span] - pub attr_span: Span, - #[label("this struct has default field values")] - pub defn_span: Span, -} - #[derive(Diagnostic)] #[diag("`#[doc(alias = \"...\")]` isn't allowed on {$location}")] pub(crate) struct DocAliasBadLocation<'a> { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 4c8000c28f065..1fab7a37a9941 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -188,6 +188,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { &i.attrs, i.span, Target::MacroDef, + None, std::convert::identity, |_lint_id, _span, _kind| { // FIXME(jdonszelmann): emit lints here properly From cca9f306f0b47a1ad9c51ff7083eb5989db104bc Mon Sep 17 00:00:00 2001 From: FractalFir Date: Tue, 5 Aug 2025 18:20:13 +0200 Subject: [PATCH 12/29] Refactored the handling of the indirect return pointer in cg_ssa to allow for more correct ABI handling in cg_gcc --- compiler/rustc_codegen_llvm/src/asm.rs | 4 +- compiler/rustc_codegen_llvm/src/builder.rs | 40 ++++-- compiler/rustc_codegen_llvm/src/intrinsic.rs | 118 ++++++++++++++++-- compiler/rustc_codegen_ssa/src/base.rs | 5 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 47 ++++--- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 1 + compiler/rustc_codegen_ssa/src/size_of_val.rs | 1 + .../rustc_codegen_ssa/src/traits/builder.rs | 2 + 8 files changed, 181 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index c22318c0ec8a7..aa1db69152e57 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -586,9 +586,9 @@ pub(crate) fn inline_asm_call<'ll>( assert!(catch_funclet.is_none()); bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None) } else if let Some((catch, funclet)) = catch_funclet { - bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet, None) + bx.invoke(fty, None, None, v, None /*FIXME(FractalFir): I assume that inline assembly does not return via `PassMode::Indirect` - is this correct?*/, inputs, dest.unwrap(), catch, funclet, None) } else { - bx.call(fty, None, None, v, inputs, None, None) + bx.call(fty, None, None, v, None /*FIXME(FractalFir): I assume that inline assembly does not return via `PassMode::Indirect` - is this correct?*/,inputs, None, None) }; // Store mark in a metadata node so we can map LLVM errors diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index dae8b2d17e0e1..e6a620372e6af 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -454,15 +454,24 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, llfn: &'ll Value, + indirect_return_pointer: Option, args: &[&'ll Value], then: &'ll BasicBlock, catch: &'ll BasicBlock, funclet: Option<&Funclet<'ll>>, instance: Option>, ) -> &'ll Value { + let args = match indirect_return_pointer { + None => args.to_vec(), + Some(sret_ptr) => { + let mut args = args.to_vec(); + // Preappend the indirect return pointer + args.insert(0, sret_ptr); + args + } + }; debug!("invoke {:?} with args ({:?})", llfn, args); - - let args = self.check_call("invoke", llty, llfn, args); + let args = self.check_call("invoke", llty, llfn, &args); let funclet_bundle = funclet.map(|funclet| funclet.bundle()); let mut bundles: SmallVec<[_; 2]> = SmallVec::new(); if let Some(funclet_bundle) = funclet_bundle { @@ -1463,13 +1472,22 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { caller_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, llfn: &'ll Value, + indirect_return_pointer: Option, args: &[&'ll Value], funclet: Option<&Funclet<'ll>>, callee_instance: Option>, ) -> &'ll Value { + let args = match indirect_return_pointer { + None => args.to_vec(), + Some(sret_ptr) => { + let mut args = args.to_vec(); + // Preappend the indirect return pointer + args.insert(0, sret_ptr); + args + } + }; debug!("call {:?} with args ({:?})", llfn, args); - - let args = self.check_call("call", llty, llfn, args); + let args = self.check_call("call", llty, llfn, &args); let funclet_bundle = funclet.map(|funclet| funclet.bundle()); let mut bundles: SmallVec<[_; 2]> = SmallVec::new(); if let Some(funclet_bundle) = funclet_bundle { @@ -1534,8 +1552,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { funclet: Option<&Self::Funclet>, callee_instance: Option>, ) { - let call = - self.call(llty, caller_attrs, Some(fn_abi), llfn, args, funclet, callee_instance); + let call = self.call( + llty, + caller_attrs, + Some(fn_abi), + llfn, + None, /*FIXME(FractalFir): can tail calls return indrectly?*/ + args, + funclet, + callee_instance, + ); llvm::LLVMSetTailCallKind(call, llvm::TailCallKind::MustTail); match &fn_abi.ret.mode { @@ -1875,7 +1901,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { args: &[&'ll Value], ) -> &'ll Value { let (ty, f) = self.cx.get_intrinsic(base_name.into(), type_params); - self.call(ty, None, None, f, args, None, None) + self.call(ty, None, None, f, None/* FIXME(FractalFir): I **assume** that no LLVM intrinsic returns a value via sret. Is this correct?*/, args, None, None) } fn call_lifetime_intrinsic(&mut self, intrinsic: &'static str, ptr: &'ll Value, size: Size) { diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 1844a8e5c0bca..5c65b6f21aac7 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1354,7 +1354,16 @@ fn catch_unwind_intrinsic<'ll, 'tcx>( ) -> &'ll Value { if !bx.sess().panic_strategy().unwinds() { 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); + bx.call( + try_func_ty, + None, + None, + try_func, + None, /* this function can't return indirectly */ + &[data], + None, + None, + ); // Return 0 unconditionally from the intrinsic call; // we can never unwind. bx.const_bool(false) @@ -1452,7 +1461,18 @@ fn codegen_msvc_try<'ll, 'tcx>( let ptr_align = bx.tcx().data_layout.pointer_align().abi; let slot = bx.alloca(ptr_size, ptr_align); let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); - bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None, None); + bx.invoke( + try_func_ty, + None, + None, + try_func, + None, /* this function can't return indirectly */ + &[data], + normal, + catchswitch, + None, + None, + ); bx.switch_to_block(normal); bx.ret(bx.const_bool(false)); @@ -1500,7 +1520,16 @@ fn codegen_msvc_try<'ll, 'tcx>( let funclet = bx.catch_pad(cs, &[tydesc, flags, slot]); let ptr = bx.load(bx.type_ptr(), slot, ptr_align); let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void()); - bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet), None); + bx.call( + catch_ty, + None, + None, + catch_func, + None, /* this function can't return indirectly */ + &[data, ptr], + Some(&funclet), + None, + ); bx.catch_ret(&funclet, caught); // The flag value of 64 indicates a "catch-all". @@ -1508,7 +1537,16 @@ fn codegen_msvc_try<'ll, 'tcx>( let flags = bx.const_i32(64); let null = bx.const_null(bx.type_ptr()); let funclet = bx.catch_pad(cs, &[null, flags, null]); - bx.call(catch_ty, None, None, catch_func, &[data, null], Some(&funclet), None); + bx.call( + catch_ty, + None, + None, + catch_func, + None, /* this function can't return indirectly */ + &[data, null], + Some(&funclet), + None, + ); bx.catch_ret(&funclet, caught); bx.switch_to_block(caught); @@ -1517,7 +1555,16 @@ fn codegen_msvc_try<'ll, 'tcx>( // 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 ret = bx.call( + llty, + None, + None, + llfn, + None, /* this function can't return indirectly */ + &[try_func, data, catch_func], + None, + None, + ); ret } @@ -1564,7 +1611,18 @@ fn codegen_wasm_try<'ll, 'tcx>( // } // let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); - bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None, None); + bx.invoke( + try_func_ty, + None, + None, + try_func, + None, /* this function can't return indirectly */ + &[data], + normal, + catchswitch, + None, + None, + ); bx.switch_to_block(normal); bx.ret(bx.const_bool(false)); @@ -1580,7 +1638,16 @@ fn codegen_wasm_try<'ll, 'tcx>( let _sel = bx.call_intrinsic("llvm.wasm.get.ehselector", &[], &[funclet.cleanuppad()]); let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void()); - bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet), None); + bx.call( + catch_ty, + None, + None, + catch_func, + None, /* this function can't return indirectly */ + &[data, ptr], + Some(&funclet), + None, + ); bx.catch_ret(&funclet, caught); bx.switch_to_block(caught); @@ -1589,7 +1656,16 @@ fn codegen_wasm_try<'ll, 'tcx>( // 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 ret = bx.call( + llty, + None, + None, + llfn, + None, /* this function can't return indirectly */ + &[try_func, data, catch_func], + None, + None, + ); ret } @@ -1630,7 +1706,18 @@ fn codegen_gnu_try<'ll, 'tcx>( let data = llvm::get_param(bx.llfn(), 1); let catch_func = llvm::get_param(bx.llfn(), 2); let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); - bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None, None); + bx.invoke( + try_func_ty, + None, + None, + try_func, + None, /* this function can't return indirectly */ + &[data], + then, + catch, + None, + None, + ); bx.switch_to_block(then); bx.ret(bx.const_bool(false)); @@ -1648,13 +1735,22 @@ fn codegen_gnu_try<'ll, 'tcx>( bx.add_clause(vals, tydesc); let ptr = bx.extract_value(vals, 0); let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void()); - bx.call(catch_ty, None, None, catch_func, &[data, ptr], None, None); + bx.call(catch_ty, None, None, catch_func, None, &[data, ptr], None, None); bx.ret(bx.const_bool(true)); }); // 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 ret = bx.call( + llty, + None, + None, + llfn, + None, /* this function can't return indirectly */ + &[try_func, data, catch_func], + None, + None, + ); ret } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 8dd129f45cc5a..b1d6cf6e5a605 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -593,7 +593,10 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ) }; - let result = bx.call(start_ty, None, None, start_fn, &args, None, instance); + let result = bx.call( + start_ty, None, None, start_fn, None, /*The entry fn does not return indirectly.*/ + &args, None, instance, + ); if cx.sess().target.os == Os::Uefi { bx.ret(result); } else { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index afd9a88784c2f..f48b9f9c83d3b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -171,6 +171,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { bx: &mut Bx, fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>, fn_ptr: Bx::Value, + indirect_return_pointer: Option, llargs: &[Bx::Value], destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>, mut unwind: mir::UnwindAction, @@ -260,6 +261,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { caller_attrs, Some(fn_abi), fn_ptr, + indirect_return_pointer, llargs, ret_llbb, unwind_block, @@ -291,6 +293,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { caller_attrs, Some(fn_abi), fn_ptr, + indirect_return_pointer, llargs, self.funclet(fx), instance, @@ -718,6 +721,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx, fn_abi, drop_fn, + None, /*Drops always return nothing, so they can't have an indirect return.*/ args, Some((ReturnDest::Nothing, target)), unwind, @@ -822,6 +826,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx, fn_abi, llfn, + None, /*The assert functions don't return anything, so they can't return indirectly*/ &args, None, unwind, @@ -853,6 +858,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx, fn_abi, llfn, + None /*The codegen terminator does not return anything - so it can't have indirect reutns*/, &[], None, mir::UnwindAction::Unreachable, @@ -922,6 +928,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx, fn_abi, llfn, + None, /*Panics return nothing, so they can't have an indirect return.*/ &[msg.0, msg.1], target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)), unwind, @@ -1202,21 +1209,22 @@ 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 destination = match kind { + let (destination, indirect_return) = match kind { CallKind::Normal => { - let return_dest = self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs); - target.map(|target| (return_dest, target)) + let (return_dest, indirect_return) = + self.make_return_dest(bx, destination, &fn_abi.ret); + (target.map(|target| (return_dest, target)), indirect_return) } CallKind::Tail => { if fn_abi.ret.is_indirect() { - match self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs) { - ReturnDest::Nothing => {} + match self.make_return_dest(bx, destination, &fn_abi.ret) { + (ReturnDest::Nothing, _) => {} _ => bug!( "tail calls to functions with indirect returns cannot store into a destination" ), } } - None + (None, None) } }; @@ -1441,6 +1449,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx, fn_abi, fn_ptr, + indirect_return, &llargs, destination, unwind, @@ -2360,7 +2369,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } else { let fn_ty = bx.fn_decl_backend_type(fn_abi); - let llret = bx.call(fn_ty, None, Some(fn_abi), fn_ptr, &[], funclet.as_ref(), None); + let llret = bx.call( + fn_ty, + None, + Some(fn_abi), + fn_ptr, + None, /*This function does not return indirectly.*/ + &[], + funclet.as_ref(), + None, + ); bx.apply_attrs_to_cleanup_callsite(llret); } @@ -2396,11 +2414,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx: &mut Bx, dest: mir::Place<'tcx>, fn_ret: &ArgAbi<'tcx, Ty<'tcx>>, - llargs: &mut Vec, - ) -> ReturnDest<'tcx, Bx::Value> { + ) -> (ReturnDest<'tcx, Bx::Value>, Option) { // If the return is ignored, we can just return a do-nothing `ReturnDest`. if fn_ret.is_ignore() { - return ReturnDest::Nothing; + return (ReturnDest::Nothing, None); } let dest = if let Some(index) = dest.as_local() { match self.locals[index] { @@ -2414,10 +2431,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // but the calling convention has an indirect return. let tmp = PlaceRef::alloca(bx, fn_ret.layout); tmp.storage_live(bx); - llargs.push(tmp.val.llval); - ReturnDest::IndirectOperand(tmp, index) + (ReturnDest::IndirectOperand(tmp, index), Some(tmp.val.llval)) } else { - ReturnDest::DirectOperand(index) + (ReturnDest::DirectOperand(index), None) }; } LocalRef::Operand(_) => { @@ -2437,10 +2453,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // to create a temporary. span_bug!(self.mir.span, "can't directly store to unaligned value"); } - llargs.push(dest.val.llval); - ReturnDest::Nothing + (ReturnDest::Nothing, Some(dest.val.llval)) } else { - ReturnDest::Store(dest) + (ReturnDest::Store(dest), None) } } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 344a4834862e4..2b1d57d9b0151 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -779,6 +779,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn_attrs.as_deref(), Some(fn_abi), fn_ptr, + None, /*The TLS shim does not return indirectly*/ &[], None, Some(instance), diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index 0ef0179eac6c4..289597b9e1634 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -78,6 +78,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( /* fn_attrs */ None, Some(fn_abi), llfn, + None,/*We know the ABI of this intrinc, and we know it does not require an indirect reutrn pointer*/ &[msg.0, msg.1], None, None, diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index cb0209a0ae369..80ac563d6d875 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -135,6 +135,7 @@ pub trait BuilderMethods<'a, 'tcx>: fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, llfn: Self::Value, + indirect_return_pointer: Option, args: &[Self::Value], then: Self::BasicBlock, catch: Self::BasicBlock, @@ -648,6 +649,7 @@ pub trait BuilderMethods<'a, 'tcx>: caller_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, fn_val: Self::Value, + indirect_return_pointer: Option, args: &[Self::Value], funclet: Option<&Self::Funclet>, callee_instance: Option>, From e6b7dc81529b801f030e35e1ccf768329c38dc34 Mon Sep 17 00:00:00 2001 From: FractalFir Date: Tue, 5 Aug 2025 22:12:26 +0200 Subject: [PATCH 13/29] Ported cg_gcc to the new cg_ssa version --- compiler/rustc_codegen_gcc/src/builder.rs | 23 +++++++++-- .../rustc_codegen_gcc/src/intrinsic/mod.rs | 39 ++++++++++++++++--- compiler/rustc_codegen_llvm/src/builder.rs | 17 +++++--- compiler/rustc_codegen_ssa/src/mir/block.rs | 3 ++ compiler/rustc_codegen_ssa/src/size_of_val.rs | 2 +- 5 files changed, 69 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 88049d67964b1..29155abee276c 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -608,6 +608,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, + indirect_return_pointer: Option>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, @@ -618,7 +619,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let current_block = self.block; self.block = try_block; - let call = self.call(typ, fn_attrs, fn_abi, func, args, None, instance); // FIXME(antoyo): use funclet here? + let call = + self.call(typ, fn_attrs, fn_abi, func, indirect_return_pointer, args, None, instance); // FIXME(antoyo): use funclet here? self.block = current_block; let return_value = @@ -646,13 +648,15 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, + indirect_return_pointer: Option>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>, instance: Option>, ) -> RValue<'gcc> { - let call_site = self.call(typ, fn_attrs, fn_abi, func, args, None, instance); + let call_site = + self.call(typ, fn_attrs, fn_abi, func, indirect_return_pointer, args, None, instance); let condition = self.context.new_rvalue_from_int(self.bool_type, 1); self.llbb().end_with_conditional(self.location, condition, then, catch); if let Some(_fn_abi) = fn_abi { @@ -1779,19 +1783,30 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { _fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, + indirect_return_pointer: Option>, args: &[RValue<'gcc>], funclet: Option<&Funclet>, _instance: Option>, ) -> RValue<'gcc> { + // FIXME: change this in the `rustc_codegen_gcc` repo after the sync, to use the `libgccjit` indirect return suppport. + let args = match indirect_return_pointer { + None => args.to_vec(), + Some(sret_ptr) => { + let mut args = args.to_vec(); + // Preappend the indirect return pointer + args.insert(0, sret_ptr); + args + } + }; // FIXME(antoyo): remove when having a proper API. let gcc_func = unsafe { std::mem::transmute::, Function<'gcc>>(func) }; let call = if self.functions.borrow().values().any(|value| *value == gcc_func) { // FIXME(antoyo): remove when the API supports a different type for functions. let func: Function<'gcc> = self.cx.rvalue_as_function(func); - self.function_call(func, args, funclet) + self.function_call(func, &args, funclet) } else { // If it's a not function that was defined, it's a function pointer. - self.function_ptr_call(typ, fn_abi, func, args, funclet) + self.function_ptr_call(typ, fn_abi, func, &args, funclet) }; if let Some(_fn_abi) = fn_abi { // FIXME(bjorn3): Apply function attributes diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 5550d22b33aa3..4dc24cfa1d3ee 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -666,7 +666,16 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc fn abort(&mut self) { let func = self.context.get_builtin_function("abort"); let func: RValue<'gcc> = unsafe { std::mem::transmute(func) }; - self.call(self.type_void(), None, None, func, &[], None, None); + self.call( + self.type_void(), + None, + None, + func, + None, /* abort does not return, so it can't return indirectly. */ + &[], + None, + None, + ); } fn assume(&mut self, value: Self::Value) { @@ -1347,7 +1356,7 @@ fn try_intrinsic<'a, 'b, 'gcc, 'tcx>( let param_type = bx.u8_type.make_pointer(); let fn_type = bx.context.new_function_pointer_type(None, bx.type_void(), &[param_type], false); - bx.call(fn_type, None, None, try_func, &[data], None, None); + bx.call(fn_type, None, None, try_func, None, &[data], None, None); // Return 0 unconditionally from the intrinsic call; // we can never unwind. OperandValue::Immediate(bx.const_bool(false)).store(bx, dest); @@ -1420,21 +1429,41 @@ fn codegen_gnu_try<'gcc, 'tcx>( let zero = bx.cx.context.new_rvalue_zero(bx.int_type); let ptr = bx.cx.context.new_call(None, eh_pointer_builtin, &[zero]); let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void()); - bx.call(catch_ty, None, None, catch_func, &[data, ptr], None, None); + bx.call(catch_ty, None, None, catch_func, None, &[data, ptr], None, None); bx.ret(bx.const_bool(true)); // NOTE: the blocks must be filled before adding the try/catch, otherwise gcc will not // generate a try/catch. // FIXME(antoyo): add a check in the libgccjit API to prevent this. bx.switch_to_block(current_block); - bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None, None); + bx.invoke( + try_func_ty, + None, + None, + try_func, + None, /* this function can't return indirectly */ + &[data], + then, + catch, + None, + None, + ); }); let func = unsafe { std::mem::transmute::, RValue<'gcc>>(func) }; // 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 ret = bx.call( + llty, + None, + None, + func, + None, /*This function can't return indirectly*/ + &[try_func, data, catch_func], + None, + None, + ); OperandValue::Immediate(ret).store(bx, dest); } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index e6a620372e6af..d2c23c7a9929f 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -454,18 +454,20 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, llfn: &'ll Value, - indirect_return_pointer: Option, + indirect_return_pointer: Option<&'ll Value>, args: &[&'ll Value], then: &'ll BasicBlock, catch: &'ll BasicBlock, funclet: Option<&Funclet<'ll>>, instance: Option>, ) -> &'ll Value { + // If this function returns indirectly(`PassMode::Indirect`), + // the `indirect_return_pointer` should be the first argument. let args = match indirect_return_pointer { None => args.to_vec(), Some(sret_ptr) => { let mut args = args.to_vec(); - // Preappend the indirect return pointer + // Preappend the indirect return pointer. args.insert(0, sret_ptr); args } @@ -1472,11 +1474,13 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { caller_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, llfn: &'ll Value, - indirect_return_pointer: Option, + indirect_return_pointer: Option<&'ll Value>, args: &[&'ll Value], funclet: Option<&Funclet<'ll>>, callee_instance: Option>, ) -> &'ll Value { + // If this function returns indirectly(`PassMode::Indirect`), + // the `indirect_return_pointer` should be the first argument. let args = match indirect_return_pointer { None => args.to_vec(), Some(sret_ptr) => { @@ -1557,7 +1561,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { caller_attrs, Some(fn_abi), llfn, - None, /*FIXME(FractalFir): can tail calls return indrectly?*/ + None, /* + FIXME(FractalFir): Tail calls don't support indirect returns at the time of writing, but they will do so soon. + Once this support is added, the indirect return pointer ought to be passed here(if present). + */ args, funclet, callee_instance, @@ -1901,7 +1908,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { args: &[&'ll Value], ) -> &'ll Value { let (ty, f) = self.cx.get_intrinsic(base_name.into(), type_params); - self.call(ty, None, None, f, None/* FIXME(FractalFir): I **assume** that no LLVM intrinsic returns a value via sret. Is this correct?*/, args, None, None) + self.call(ty, None, None, f, None/* (FractalFir): at the time of writing, no LLVM intrinsic retruns data indirectly(via `sret`). So, this is always None.*/, args, None, None) } fn call_lifetime_intrinsic(&mut self, intrinsic: &'static str, ptr: &'ll Value, size: Size) { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index f48b9f9c83d3b..7dc9f600a3b50 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -165,6 +165,9 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { /// Call `fn_ptr` of `fn_abi` with the arguments `llargs`, the optional /// return destination `destination` and the unwind action `unwind`. + /// The `indirect_return_pointer` is specified for functions returning + /// via `PassMode::indirect`, and points to a buffer, where the return value + /// shall be stored. fn do_call>( &self, fx: &mut FunctionCx<'a, 'tcx, Bx>, diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index 289597b9e1634..5b4da7bb454cc 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -78,7 +78,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( /* fn_attrs */ None, Some(fn_abi), llfn, - None,/*We know the ABI of this intrinc, and we know it does not require an indirect reutrn pointer*/ + None,/*We know the ABI of this intrinc, and we know it does not require an indirect return pointer*/ &[msg.0, msg.1], None, None, From 74bba56ab9c96992539f301cf8949f74c3576119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fractal=20Fir=28Micha=C5=82=20Kostrubiec=29?= Date: Fri, 19 Sep 2025 20:23:52 +0200 Subject: [PATCH 14/29] Apply suggestions from code review Co-authored-by: Jubilee --- compiler/rustc_codegen_gcc/src/builder.rs | 2 +- compiler/rustc_codegen_ssa/src/size_of_val.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 29155abee276c..9b74512b6ac88 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1793,7 +1793,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { None => args.to_vec(), Some(sret_ptr) => { let mut args = args.to_vec(); - // Preappend the indirect return pointer + // Prepend the indirect return pointer args.insert(0, sret_ptr); args } diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index 5b4da7bb454cc..296f1cb1f8b60 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -78,7 +78,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( /* fn_attrs */ None, Some(fn_abi), llfn, - None,/*We know the ABI of this intrinc, and we know it does not require an indirect return pointer*/ + None, // we know the ABI here &[msg.0, msg.1], None, None, From 43965ead44118cd2f147638d5d3a4979e3015967 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sat, 1 Nov 2025 11:11:49 -0400 Subject: [PATCH 15/29] Add missing indirect return argument to new calls --- compiler/rustc_codegen_gcc/src/intrinsic/mod.rs | 2 +- compiler/rustc_codegen_llvm/src/builder/autodiff.rs | 2 +- compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs | 4 ++-- compiler/rustc_codegen_llvm/src/mono_item.rs | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 4dc24cfa1d3ee..98aeb25573e24 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -655,7 +655,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc } // FIXME directly use the llvm intrinsic adjustment functions here - let llret = self.call(fn_ty, None, None, fn_ptr, &call_args, None, None); + let llret = self.call(fn_ty, None, None, fn_ptr, None, &call_args, None, None); if is_cleanup { self.apply_attrs_to_cleanup_callsite(llret); } diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 8cefd8dc489a9..d08ffb5bed418 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -372,7 +372,7 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( crate::typetree::add_tt(&bx, fn_to_diff, fnc_tree); } - let call = bx.call(enzyme_ty, None, None, ad_fn, &args, None, None); + let call = bx.call(enzyme_ty, None, None, ad_fn, None, &args, None, None); let fn_ret_ty = bx.cx.val_ty(call); if fn_ret_ty == bx.cx.type_void() || fn_ret_ty == bx.cx.type_struct(&[], false) { diff --git a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs index e2ec20226e3ce..7b7c7a7e46afc 100644 --- a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs +++ b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs @@ -681,7 +681,7 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>( let num_args = cx.get_const_i32(num_args); let args = vec![s_ident_t, i64_max, num_args, geps[0], geps[1], geps[2], o_type, nullptr, nullptr]; - builder.call(fn_ty, None, None, fn_to_call, &args, None, None); + builder.call(fn_ty, None, None, fn_to_call, None, &args, None, None); } // Step 2) @@ -718,7 +718,7 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>( let device_id = builder.sext(device_id, cx.type_i64()); let args = vec![s_ident_t, device_id, num_workgroups, threads_per_block, region_id, a5]; - builder.call(tgt_target_kernel_ty, None, None, tgt_decl, &args, None, None); + builder.call(tgt_target_kernel_ty, None, None, tgt_decl, None, &args, None, None); // %41 = call i32 @__tgt_target_kernel(ptr @1, i64 -1, i32 2097152, i32 256, ptr @.kernel_1.region_id, ptr %kernel_args) // Step 4) diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index d67156c6cfa39..4fb4f32fad590 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -203,6 +203,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { Some(attrs), Some(fn_abi), aliasee, + None, &args, None, Some(aliasee_instance), From a714a9e8df9ddfa0f61eb3b8bff217e5601133d5 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 19 Jul 2026 17:08:54 -0400 Subject: [PATCH 16/29] Improve the new indirect return API --- compiler/rustc_codegen_gcc/src/builder.rs | 22 +++--- .../rustc_codegen_gcc/src/intrinsic/mod.rs | 24 +++---- compiler/rustc_codegen_llvm/src/asm.rs | 15 +++- compiler/rustc_codegen_llvm/src/builder.rs | 31 ++++---- .../src/builder/autodiff.rs | 4 +- .../src/builder/gpu_offload.rs | 6 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 31 +++----- compiler/rustc_codegen_llvm/src/mono_item.rs | 12 +++- compiler/rustc_codegen_ssa/src/base.rs | 6 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 70 ++++++++++++------- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- compiler/rustc_codegen_ssa/src/size_of_val.rs | 2 +- .../rustc_codegen_ssa/src/traits/builder.rs | 26 +++++-- compiler/rustc_codegen_ssa/src/traits/mod.rs | 2 +- 14 files changed, 144 insertions(+), 109 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 9b74512b6ac88..83f2bcdd3959c 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -18,7 +18,7 @@ use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{ BackendTypes, BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, - LayoutTypeCodegenMethods, OverflowOp, StaticBuilderMethods, + LayoutTypeCodegenMethods, OverflowOp, ReturnSlot, StaticBuilderMethods, }; use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; @@ -608,7 +608,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, - indirect_return_pointer: Option>, + return_slot: ReturnSlot>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, @@ -619,8 +619,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let current_block = self.block; self.block = try_block; - let call = - self.call(typ, fn_attrs, fn_abi, func, indirect_return_pointer, args, None, instance); // FIXME(antoyo): use funclet here? + // FIXME(antoyo): use funclet here? + let call = self.call(typ, fn_attrs, fn_abi, func, return_slot, args, None, instance); self.block = current_block; let return_value = @@ -648,15 +648,14 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, - indirect_return_pointer: Option>, + return_slot: ReturnSlot>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>, instance: Option>, ) -> RValue<'gcc> { - let call_site = - self.call(typ, fn_attrs, fn_abi, func, indirect_return_pointer, args, None, instance); + let call_site = self.call(typ, fn_attrs, fn_abi, func, return_slot, args, None, instance); let condition = self.context.new_rvalue_from_int(self.bool_type, 1); self.llbb().end_with_conditional(self.location, condition, then, catch); if let Some(_fn_abi) = fn_abi { @@ -1783,15 +1782,15 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { _fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, - indirect_return_pointer: Option>, + return_slot: ReturnSlot>, args: &[RValue<'gcc>], funclet: Option<&Funclet>, _instance: Option>, ) -> RValue<'gcc> { // FIXME: change this in the `rustc_codegen_gcc` repo after the sync, to use the `libgccjit` indirect return suppport. - let args = match indirect_return_pointer { - None => args.to_vec(), - Some(sret_ptr) => { + let args = match return_slot { + ReturnSlot::Direct => args.to_vec(), + ReturnSlot::Indirect(sret_ptr) => { let mut args = args.to_vec(); // Prepend the indirect return pointer args.insert(0, sret_ptr); @@ -1820,6 +1819,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { _fn_attrs: Option<&CodegenFnAttrs>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _llfn: Self::Value, + _return_slot: ReturnSlot, _args: &[Self::Value], _funclet: Option<&Self::Funclet>, _instance: Option>, diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 98aeb25573e24..06713016cedbe 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -16,7 +16,7 @@ use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue}; use rustc_codegen_ssa::traits::MiscCodegenMethods; use rustc_codegen_ssa::traits::{ ArgAbiBuilderMethods, BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods, - IntrinsicCallBuilderMethods, LayoutTypeCodegenMethods, + IntrinsicCallBuilderMethods, LayoutTypeCodegenMethods, ReturnSlot, }; use rustc_codegen_ssa::{MemFlags, RetagInfo}; use rustc_data_structures::fx::FxHashSet; @@ -655,7 +655,8 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc } // FIXME directly use the llvm intrinsic adjustment functions here - let llret = self.call(fn_ty, None, None, fn_ptr, None, &call_args, None, None); + let llret = + self.call(fn_ty, None, None, fn_ptr, ReturnSlot::Direct, &call_args, None, None); if is_cleanup { self.apply_attrs_to_cleanup_callsite(llret); } @@ -666,16 +667,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc fn abort(&mut self) { let func = self.context.get_builtin_function("abort"); let func: RValue<'gcc> = unsafe { std::mem::transmute(func) }; - self.call( - self.type_void(), - None, - None, - func, - None, /* abort does not return, so it can't return indirectly. */ - &[], - None, - None, - ); + self.call(self.type_void(), None, None, func, ReturnSlot::Direct, &[], None, None); } fn assume(&mut self, value: Self::Value) { @@ -1356,7 +1348,7 @@ fn try_intrinsic<'a, 'b, 'gcc, 'tcx>( let param_type = bx.u8_type.make_pointer(); let fn_type = bx.context.new_function_pointer_type(None, bx.type_void(), &[param_type], false); - bx.call(fn_type, None, None, try_func, None, &[data], None, None); + bx.call(fn_type, None, None, try_func, ReturnSlot::Direct, &[data], None, None); // Return 0 unconditionally from the intrinsic call; // we can never unwind. OperandValue::Immediate(bx.const_bool(false)).store(bx, dest); @@ -1429,7 +1421,7 @@ fn codegen_gnu_try<'gcc, 'tcx>( let zero = bx.cx.context.new_rvalue_zero(bx.int_type); let ptr = bx.cx.context.new_call(None, eh_pointer_builtin, &[zero]); let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void()); - bx.call(catch_ty, None, None, catch_func, None, &[data, ptr], None, None); + bx.call(catch_ty, None, None, catch_func, ReturnSlot::Direct, &[data, ptr], None, None); bx.ret(bx.const_bool(true)); // NOTE: the blocks must be filled before adding the try/catch, otherwise gcc will not @@ -1441,7 +1433,7 @@ fn codegen_gnu_try<'gcc, 'tcx>( None, None, try_func, - None, /* this function can't return indirectly */ + ReturnSlot::Direct, &[data], then, catch, @@ -1459,7 +1451,7 @@ fn codegen_gnu_try<'gcc, 'tcx>( None, None, func, - None, /*This function can't return indirectly*/ + ReturnSlot::Direct, &[try_func, data, catch_func], None, None, diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index aa1db69152e57..8e5750a2998bc 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -586,9 +586,20 @@ pub(crate) fn inline_asm_call<'ll>( assert!(catch_funclet.is_none()); bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None) } else if let Some((catch, funclet)) = catch_funclet { - bx.invoke(fty, None, None, v, None /*FIXME(FractalFir): I assume that inline assembly does not return via `PassMode::Indirect` - is this correct?*/, inputs, dest.unwrap(), catch, funclet, None) + bx.invoke( + fty, + None, + None, + v, + ReturnSlot::Direct, + inputs, + dest.unwrap(), + catch, + funclet, + None, + ) } else { - bx.call(fty, None, None, v, None /*FIXME(FractalFir): I assume that inline assembly does not return via `PassMode::Indirect` - is this correct?*/,inputs, None, None) + bx.call(fty, None, None, v, ReturnSlot::Direct, inputs, None, None) }; // Store mark in a metadata node so we can map LLVM errors diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index d2c23c7a9929f..f0772e5b3e1b2 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -454,7 +454,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, llfn: &'ll Value, - indirect_return_pointer: Option<&'ll Value>, + return_slot: ReturnSlot<&'ll Value>, args: &[&'ll Value], then: &'ll BasicBlock, catch: &'ll BasicBlock, @@ -462,12 +462,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { instance: Option>, ) -> &'ll Value { // If this function returns indirectly(`PassMode::Indirect`), - // the `indirect_return_pointer` should be the first argument. - let args = match indirect_return_pointer { - None => args.to_vec(), - Some(sret_ptr) => { + // the `return_slot` should be the first argument. + let args = match return_slot { + ReturnSlot::Direct => args.to_vec(), + ReturnSlot::Indirect(sret_ptr) => { let mut args = args.to_vec(); - // Preappend the indirect return pointer. args.insert(0, sret_ptr); args } @@ -1474,18 +1473,17 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { caller_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, llfn: &'ll Value, - indirect_return_pointer: Option<&'ll Value>, + return_slot: ReturnSlot<&'ll Value>, args: &[&'ll Value], funclet: Option<&Funclet<'ll>>, callee_instance: Option>, ) -> &'ll Value { // If this function returns indirectly(`PassMode::Indirect`), - // the `indirect_return_pointer` should be the first argument. - let args = match indirect_return_pointer { - None => args.to_vec(), - Some(sret_ptr) => { + // the `return_slot` should be the first argument. + let args = match return_slot { + ReturnSlot::Direct => args.to_vec(), + ReturnSlot::Indirect(sret_ptr) => { let mut args = args.to_vec(); - // Preappend the indirect return pointer args.insert(0, sret_ptr); args } @@ -1552,6 +1550,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { caller_attrs: Option<&CodegenFnAttrs>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, llfn: Self::Value, + return_slot: ReturnSlot, args: &[Self::Value], funclet: Option<&Self::Funclet>, callee_instance: Option>, @@ -1561,10 +1560,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { caller_attrs, Some(fn_abi), llfn, - None, /* - FIXME(FractalFir): Tail calls don't support indirect returns at the time of writing, but they will do so soon. - Once this support is added, the indirect return pointer ought to be passed here(if present). - */ + return_slot, args, funclet, callee_instance, @@ -1908,7 +1904,8 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { args: &[&'ll Value], ) -> &'ll Value { let (ty, f) = self.cx.get_intrinsic(base_name.into(), type_params); - self.call(ty, None, None, f, None/* (FractalFir): at the time of writing, no LLVM intrinsic retruns data indirectly(via `sret`). So, this is always None.*/, args, None, None) + // No LLVM intrinsic returns its data indirectly (via `sret`). + self.call(ty, None, None, f, ReturnSlot::Direct, args, None, None) } fn call_lifetime_intrinsic(&mut self, intrinsic: &'static str, ptr: &'ll Value, size: Size) { diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index d08ffb5bed418..3831f3b0912fd 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -6,7 +6,7 @@ use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::mir::IntrinsicResult; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceValue; -use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods}; +use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods, ReturnSlot}; use rustc_data_structures::thin_vec::ThinVec; use rustc_hir::attrs::RustcAutodiff; use rustc_middle::ty::{PseudoCanonicalInput, Ty, TyCtxt, TypingEnv}; @@ -372,7 +372,7 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>( crate::typetree::add_tt(&bx, fn_to_diff, fnc_tree); } - let call = bx.call(enzyme_ty, None, None, ad_fn, None, &args, None, None); + let call = bx.call(enzyme_ty, None, None, ad_fn, ReturnSlot::Direct, &args, None, None); let fn_ret_ty = bx.cx.val_ty(call); if fn_ret_ty == bx.cx.type_void() || fn_ret_ty == bx.cx.type_struct(&[], false) { diff --git a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs index 7b7c7a7e46afc..a84ca02cc3b18 100644 --- a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs +++ b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs @@ -6,7 +6,7 @@ use rustc_abi::Align; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; -use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods}; +use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods, ReturnSlot}; use rustc_middle::bug; use rustc_middle::ty::offload_meta::{MappingFlags, OffloadMetadata, OffloadSize}; @@ -681,7 +681,7 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>( let num_args = cx.get_const_i32(num_args); let args = vec![s_ident_t, i64_max, num_args, geps[0], geps[1], geps[2], o_type, nullptr, nullptr]; - builder.call(fn_ty, None, None, fn_to_call, None, &args, None, None); + builder.call(fn_ty, None, None, fn_to_call, ReturnSlot::Direct, &args, None, None); } // Step 2) @@ -718,7 +718,7 @@ pub(crate) fn gen_call_handling<'ll, 'tcx>( let device_id = builder.sext(device_id, cx.type_i64()); let args = vec![s_ident_t, device_id, num_workgroups, threads_per_block, region_id, a5]; - builder.call(tgt_target_kernel_ty, None, None, tgt_decl, None, &args, None, None); + builder.call(tgt_target_kernel_ty, None, None, tgt_decl, ReturnSlot::Direct, &args, None, None); // %41 = call i32 @__tgt_target_kernel(ptr @1, i64 -1, i32 2097152, i32 256, ptr @.kernel_1.region_id, ptr %kernel_args) // Step 4) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 5c65b6f21aac7..fe02245627a78 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1354,16 +1354,7 @@ fn catch_unwind_intrinsic<'ll, 'tcx>( ) -> &'ll Value { if !bx.sess().panic_strategy().unwinds() { let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void()); - bx.call( - try_func_ty, - None, - None, - try_func, - None, /* this function can't return indirectly */ - &[data], - None, - None, - ); + bx.call(try_func_ty, None, None, try_func, ReturnSlot::Direct, &[data], None, None); // Return 0 unconditionally from the intrinsic call; // we can never unwind. bx.const_bool(false) @@ -1466,7 +1457,7 @@ fn codegen_msvc_try<'ll, 'tcx>( None, None, try_func, - None, /* this function can't return indirectly */ + ReturnSlot::Direct, &[data], normal, catchswitch, @@ -1525,7 +1516,7 @@ fn codegen_msvc_try<'ll, 'tcx>( None, None, catch_func, - None, /* this function can't return indirectly */ + ReturnSlot::Direct, &[data, ptr], Some(&funclet), None, @@ -1542,7 +1533,7 @@ fn codegen_msvc_try<'ll, 'tcx>( None, None, catch_func, - None, /* this function can't return indirectly */ + ReturnSlot::Direct, &[data, null], Some(&funclet), None, @@ -1560,7 +1551,7 @@ fn codegen_msvc_try<'ll, 'tcx>( None, None, llfn, - None, /* this function can't return indirectly */ + ReturnSlot::Direct, &[try_func, data, catch_func], None, None, @@ -1616,7 +1607,7 @@ fn codegen_wasm_try<'ll, 'tcx>( None, None, try_func, - None, /* this function can't return indirectly */ + ReturnSlot::Direct, &[data], normal, catchswitch, @@ -1643,7 +1634,7 @@ fn codegen_wasm_try<'ll, 'tcx>( None, None, catch_func, - None, /* this function can't return indirectly */ + ReturnSlot::Direct, &[data, ptr], Some(&funclet), None, @@ -1661,7 +1652,7 @@ fn codegen_wasm_try<'ll, 'tcx>( None, None, llfn, - None, /* this function can't return indirectly */ + ReturnSlot::Direct, &[try_func, data, catch_func], None, None, @@ -1711,7 +1702,7 @@ fn codegen_gnu_try<'ll, 'tcx>( None, None, try_func, - None, /* this function can't return indirectly */ + ReturnSlot::Direct, &[data], then, catch, @@ -1735,7 +1726,7 @@ fn codegen_gnu_try<'ll, 'tcx>( bx.add_clause(vals, tydesc); let ptr = bx.extract_value(vals, 0); let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void()); - bx.call(catch_ty, None, None, catch_func, None, &[data, ptr], None, None); + bx.call(catch_ty, None, None, catch_func, ReturnSlot::Direct, &[data, ptr], None, None); bx.ret(bx.const_bool(true)); }); @@ -1746,7 +1737,7 @@ fn codegen_gnu_try<'ll, 'tcx>( None, None, llfn, - None, /* this function can't return indirectly */ + ReturnSlot::Direct, &[try_func, data, catch_func], None, None, diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 4fb4f32fad590..e0b1df0bb632c 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -198,13 +198,21 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { args.push(llvm::get_param(alias_lldecl, index)); } + // For an indirect return, the alias's own first parameter is the + // caller-provided return slot: forward it to the aliasee as such. + let (return_slot, args) = if fn_abi.ret.is_indirect() { + let (sret_ptr, rest) = args.split_first().unwrap(); + (ReturnSlot::Indirect(*sret_ptr), rest) + } else { + (ReturnSlot::Direct, &args[..]) + }; let call = start_bx.call( fn_ty, Some(attrs), Some(fn_abi), aliasee, - None, - &args, + return_slot, + args, None, Some(aliasee_instance), ); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index b1d6cf6e5a605..d909316194566 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -593,10 +593,8 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ) }; - let result = bx.call( - start_ty, None, None, start_fn, None, /*The entry fn does not return indirectly.*/ - &args, None, instance, - ); + let result = + bx.call(start_ty, None, None, start_fn, ReturnSlot::Direct, &args, None, instance); if cx.sess().target.os == Os::Uefi { bx.ret(result); } else { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 7dc9f600a3b50..c3d66b6df2b81 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -165,8 +165,8 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { /// Call `fn_ptr` of `fn_abi` with the arguments `llargs`, the optional /// return destination `destination` and the unwind action `unwind`. - /// The `indirect_return_pointer` is specified for functions returning - /// via `PassMode::indirect`, and points to a buffer, where the return value + /// The `return_slot` is [`ReturnSlot::Indirect`] for functions returning + /// via `PassMode::Indirect`, and points to a buffer where the return value /// shall be stored. fn do_call>( &self, @@ -174,7 +174,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { bx: &mut Bx, fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>, fn_ptr: Bx::Value, - indirect_return_pointer: Option, + return_slot: ReturnSlot, llargs: &[Bx::Value], destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>, mut unwind: mir::UnwindAction, @@ -248,8 +248,23 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { } }; + debug_assert_eq!( + return_slot.is_indirect(), + fn_abi.ret.is_indirect(), + "a return slot must be provided if and only if the return is `PassMode::Indirect`", + ); + if kind == CallKind::Tail { - bx.tail_call(fn_ty, caller_attrs, fn_abi, fn_ptr, llargs, self.funclet(fx), instance); + bx.tail_call( + fn_ty, + caller_attrs, + fn_abi, + fn_ptr, + return_slot, + llargs, + self.funclet(fx), + instance, + ); return MergingSucc::False; } @@ -264,7 +279,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { caller_attrs, Some(fn_abi), fn_ptr, - indirect_return_pointer, + return_slot, llargs, ret_llbb, unwind_block, @@ -296,7 +311,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { caller_attrs, Some(fn_abi), fn_ptr, - indirect_return_pointer, + return_slot, llargs, self.funclet(fx), instance, @@ -724,7 +739,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx, fn_abi, drop_fn, - None, /*Drops always return nothing, so they can't have an indirect return.*/ + ReturnSlot::Direct, args, Some((ReturnDest::Nothing, target)), unwind, @@ -829,7 +844,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx, fn_abi, llfn, - None, /*The assert functions don't return anything, so they can't return indirectly*/ + ReturnSlot::Direct, &args, None, unwind, @@ -861,7 +876,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx, fn_abi, llfn, - None /*The codegen terminator does not return anything - so it can't have indirect reutns*/, + ReturnSlot::Direct, &[], None, mir::UnwindAction::Unreachable, @@ -931,7 +946,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx, fn_abi, llfn, - None, /*Panics return nothing, so they can't have an indirect return.*/ + ReturnSlot::Direct, &[msg.0, msg.1], target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)), unwind, @@ -1212,22 +1227,24 @@ 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 (destination, indirect_return) = match kind { + let (destination, return_slot) = match kind { CallKind::Normal => { - let (return_dest, indirect_return) = + let (return_dest, return_slot) = self.make_return_dest(bx, destination, &fn_abi.ret); - (target.map(|target| (return_dest, target)), indirect_return) + (target.map(|target| (return_dest, target)), return_slot) } CallKind::Tail => { - if fn_abi.ret.is_indirect() { + let return_slot = if fn_abi.ret.is_indirect() { match self.make_return_dest(bx, destination, &fn_abi.ret) { - (ReturnDest::Nothing, _) => {} + (ReturnDest::Nothing, return_slot) => return_slot, _ => bug!( "tail calls to functions with indirect returns cannot store into a destination" ), } - } - (None, None) + } else { + ReturnSlot::Direct + }; + (None, return_slot) } }; @@ -1452,7 +1469,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx, fn_abi, fn_ptr, - indirect_return, + return_slot, &llargs, destination, unwind, @@ -2377,7 +2394,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { None, Some(fn_abi), fn_ptr, - None, /*This function does not return indirectly.*/ + ReturnSlot::Direct, &[], funclet.as_ref(), None, @@ -2417,10 +2434,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx: &mut Bx, dest: mir::Place<'tcx>, fn_ret: &ArgAbi<'tcx, Ty<'tcx>>, - ) -> (ReturnDest<'tcx, Bx::Value>, Option) { + ) -> (ReturnDest<'tcx, Bx::Value>, ReturnSlot) { // If the return is ignored, we can just return a do-nothing `ReturnDest`. if fn_ret.is_ignore() { - return (ReturnDest::Nothing, None); + return (ReturnDest::Nothing, ReturnSlot::Direct); } let dest = if let Some(index) = dest.as_local() { match self.locals[index] { @@ -2434,9 +2451,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // but the calling convention has an indirect return. let tmp = PlaceRef::alloca(bx, fn_ret.layout); tmp.storage_live(bx); - (ReturnDest::IndirectOperand(tmp, index), Some(tmp.val.llval)) + ( + ReturnDest::IndirectOperand(tmp, index), + ReturnSlot::Indirect(tmp.val.llval), + ) } else { - (ReturnDest::DirectOperand(index), None) + (ReturnDest::DirectOperand(index), ReturnSlot::Direct) }; } LocalRef::Operand(_) => { @@ -2456,9 +2476,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // to create a temporary. span_bug!(self.mir.span, "can't directly store to unaligned value"); } - (ReturnDest::Nothing, Some(dest.val.llval)) + (ReturnDest::Nothing, ReturnSlot::Indirect(dest.val.llval)) } else { - (ReturnDest::Store(dest), None) + (ReturnDest::Store(dest), ReturnSlot::Direct) } } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 2b1d57d9b0151..6278020eabecd 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -779,7 +779,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn_attrs.as_deref(), Some(fn_abi), fn_ptr, - None, /*The TLS shim does not return indirectly*/ + ReturnSlot::Direct, &[], None, Some(instance), diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index 296f1cb1f8b60..e286681c293ee 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -78,7 +78,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( /* fn_attrs */ None, Some(fn_abi), llfn, - None, // we know the ABI here + ReturnSlot::Direct, // we know the ABI here &[msg.0, msg.1], None, None, diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 80ac563d6d875..b7b694922bcfa 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -34,6 +34,20 @@ pub enum OverflowOp { Mul, } +/// The location of the return value for the call. +#[derive(Copy, Clone, Debug)] +pub enum ReturnSlot { + Direct, + /// The return value will be passed via sret (e.g. `PassMode::Indirect`). + Indirect(V), +} + +impl ReturnSlot { + pub fn is_indirect(&self) -> bool { + matches!(self, ReturnSlot::Indirect(_)) + } +} + pub trait BuilderMethods<'a, 'tcx>: Sized + LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> @@ -135,7 +149,7 @@ pub trait BuilderMethods<'a, 'tcx>: fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, llfn: Self::Value, - indirect_return_pointer: Option, + return_slot: ReturnSlot, args: &[Self::Value], then: Self::BasicBlock, catch: Self::BasicBlock, @@ -639,17 +653,20 @@ pub trait BuilderMethods<'a, 'tcx>: /// The typical case that they are None is during the codegen of intrinsics and lang-items, /// as those are "fake functions" with only a trivial ABI if any, et cetera. /// + /// `return_slot` must be `ReturnSlot::Indirect` if an argument uses `PassMode::Indirect`. + /// /// ## Return /// - /// Must return the value the function will return so it can be written to the destination, - /// assuming the function does not explicitly pass the destination as a pointer in `args`. + /// Must return the value the function will return so it can be written to the destination. + /// For calls with an indirect return, the returned value is meaningless and must not be + /// used: the return value lives in the return slot. fn call( &mut self, llty: Self::FunctionSignature, caller_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, fn_val: Self::Value, - indirect_return_pointer: Option, + return_slot: ReturnSlot, args: &[Self::Value], funclet: Option<&Self::Funclet>, callee_instance: Option>, @@ -661,6 +678,7 @@ pub trait BuilderMethods<'a, 'tcx>: caller_attrs: Option<&CodegenFnAttrs>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, llfn: Self::Value, + return_slot: ReturnSlot, args: &[Self::Value], funclet: Option<&Self::Funclet>, callee_instance: Option>, diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index f46d07ea5008e..1f013cb122070 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -36,7 +36,7 @@ pub use self::asm::{ AsmBuilderMethods, AsmCodegenMethods, GlobalAsmOperandRef, InlineAsmOperandRef, }; pub use self::backend::{BackendTypes, CodegenBackend, ExtraBackendMethods}; -pub use self::builder::{BuilderMethods, OverflowOp}; +pub use self::builder::{BuilderMethods, OverflowOp, ReturnSlot}; pub use self::consts::ConstCodegenMethods; pub use self::coverageinfo::CoverageInfoBuilderMethods; pub use self::debuginfo::{DebugInfoBuilderMethods, DebugInfoCodegenMethods}; From d244854ed70717792deceea72677059fa1637c5d Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Mon, 27 Jul 2026 17:19:37 -0400 Subject: [PATCH 17/29] Address review --- compiler/rustc_codegen_llvm/src/builder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index f0772e5b3e1b2..e2d1941f46c8f 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -461,7 +461,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { funclet: Option<&Funclet<'ll>>, instance: Option>, ) -> &'ll Value { - // If this function returns indirectly(`PassMode::Indirect`), + // If this function returns indirectly (`PassMode::Indirect`), // the `return_slot` should be the first argument. let args = match return_slot { ReturnSlot::Direct => args.to_vec(), @@ -1478,7 +1478,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { funclet: Option<&Funclet<'ll>>, callee_instance: Option>, ) -> &'ll Value { - // If this function returns indirectly(`PassMode::Indirect`), + // If this function returns indirectly (`PassMode::Indirect`), // the `return_slot` should be the first argument. let args = match return_slot { ReturnSlot::Direct => args.to_vec(), From 7d0d2731eef519190d63231bcfe8e8a4e0fe3907 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Fri, 21 Aug 2026 08:13:30 -0400 Subject: [PATCH 18/29] Add missing direct return arguments --- compiler/rustc_codegen_llvm/src/builder.rs | 1 + compiler/rustc_codegen_llvm/src/intrinsic.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index e2d1941f46c8f..9d4602e49968d 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -2121,6 +2121,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { None, None, ubsan_handler, + ReturnSlot::Direct, &[diag_data, function_address, self.const_usize(0)], None, None, diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index fe02245627a78..be384689be39d 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -245,7 +245,8 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { sym::offload_get_num_devices => { let (fn_decl, fn_ty) = declare_omp_get_num_devices(self.cx); - let llval = self.call(fn_ty, None, None, fn_decl, &[], None, None); + let llval = + self.call(fn_ty, None, None, fn_decl, ReturnSlot::Direct, &[], None, None); return IntrinsicResult::Operand(OperandValue::Immediate(llval)); } From a5511267f0bd56a8fd6c7ea4cd33b2ab6e5acb31 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 8 Sep 2026 20:00:28 +0000 Subject: [PATCH 19/29] The fuchsia team maintains `riscv64gc-unknown-fuchsia` --- src/doc/rustc/src/platform-support.md | 2 +- src/doc/rustc/src/platform-support/fuchsia.md | 42 ++++++++++++------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 54d9885c93955..ab858f79a4020 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -415,7 +415,7 @@ target | std | host | notes [`riscv64-oe-linux-gnu`](platform-support/oe-linux-gnu.md) | ✓ | | RISC-V OpenEmbedded/Yocto Linux (GNU) [`riscv64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | `riscv64gc-unknown-freebsd` | ? | | RISC-V FreeBSD -`riscv64gc-unknown-fuchsia` | ? | | RISC-V Fuchsia +[`riscv64gc-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | | RISC-V Fuchsia [`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ | | RISC-V Hermit [`riscv64gc-unknown-managarm-mlibc`](platform-support/managarm.md) | ? | | RISC-V Managarm [`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | RISC-V NetBSD diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index e2befc5d9955b..2ce9916003393 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -7,8 +7,11 @@ updatable, and performant. ## Target maintainers -[@erickt](https://github.com/erickt) -[@Nashenas88](https://github.com/Nashenas88) +- [@Nashenas88](https://github.com/Nashenas88) +- [@PiJoules](https://github.com/PiJoules) +- [@erickt](https://github.com/erickt) +- [@ilovepi](https://github.com/ilovepi) +- [@petrhosek](https://github.com/petrhosek) The up-to-date list can be also found via the [fuchsia marker team](https://github.com/rust-lang/team/blob/master/teams/fuchsia.toml). @@ -181,12 +184,12 @@ Before building Rust for Fuchsia, you'll need a clang toolchain that supports Fuchsia as well. A recent version (14+) of clang should be sufficient to compile Rust for Fuchsia. -x86-64 and AArch64 Fuchsia targets can be enabled using the following +x86-64, AArch64, and riscv64gc Fuchsia targets can be enabled using the following configuration in `bootstrap.toml`: ```toml [build] -target = ["", "aarch64-unknown-fuchsia", "x86_64-unknown-fuchsia"] +target = ["", "aarch64-unknown-fuchsia", "x86_64-unknown-fuchsia", "riscv64gc-unknown-fuchsia"] [rust] lld = true @@ -201,6 +204,10 @@ cxx = "clang++" [target.aarch64-unknown-fuchsia] cc = "clang" cxx = "clang++" + +[target.riscv64gc-unknown-fuchsia] +cc = "clang" +cxx = "clang++" ``` Though not strictly required, you may also want to use `clang` for your host @@ -237,6 +244,10 @@ export CFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot= export CXXFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -I${SDK_PATH}/pkg/fdio/include" export LDFLAGS_x86_64_unknown_fuchsia="--target=x86_64-unknown-fuchsia --sysroot=${SDK_PATH}/arch/x64/sysroot -L${SDK_PATH}/arch/x64/lib" export CARGO_TARGET_X86_64_UNKNOWN_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=${SDK_PATH}/arch/x64/sysroot -Lnative=${SDK_PATH}/arch/x64/sysroot/lib -Lnative=${SDK_PATH}/arch/x64/lib" +export CFLAGS_riscv64gc_unknown_fuchsia="--target=riscv64gc-unknown-fuchsia --sysroot=${SDK_PATH}/arch/riscv64/sysroot -I${SDK_PATH}/pkg/fdio/include" +export CXXFLAGS_riscv64gc_unknown_fuchsia="--target=riscv64gc-unknown-fuchsia --sysroot=${SDK_PATH}/arch/riscv64/sysroot -I${SDK_PATH}/pkg/fdio/include" +export LDFLAGS_riscv64gc_unknown_fuchsia="--target=riscv64gc-unknown-fuchsia --sysroot=${SDK_PATH}/arch/riscv64/sysroot -L${SDK_PATH}/arch/riscv64/lib" +export CARGO_TARGET_RISCV64GC_UNKNOWN_FUCHSIA_RUSTFLAGS="-C link-arg=--sysroot=${SDK_PATH}/arch/riscv64/sysroot -Lnative=${SDK_PATH}/arch/riscv64/sysroot/lib -Lnative=${SDK_PATH}/arch/riscv64/lib" ``` Finally, the Rust compiler can be built and installed: @@ -281,8 +292,9 @@ hello_fuchsia/ Using your freshly installed `rustc`, you can compile a binary for Fuchsia using the following options: -* `--target x86_64-unknown-fuchsia`/`--target aarch64-unknown-fuchsia`: Targets the Fuchsia - platform of your choice +* `--target x86_64-unknown-fuchsia` / `--target aarch64-unknown-fuchsia` / + `--target riscv64gc-unknown-fuchsia`: Targets the Fuchsia platform of your + choice * `-Lnative ${SDK_PATH}/arch/${ARCH}/lib`: Link against Fuchsia libraries from the SDK * `-Lnative ${SDK_PATH}/arch/${ARCH}/sysroot/lib`: Link against Fuchsia sysroot @@ -292,8 +304,8 @@ Putting it all together: ```sh # Configure these for the Fuchsia target of your choice -TARGET_ARCH="" -ARCH="" +TARGET_ARCH="" +ARCH="" rustc \ --target ${TARGET_ARCH} \ @@ -688,12 +700,12 @@ We can then use the script to start our test environment with: ```sh ( \ - source config-env.sh && \ - src/ci/docker/scripts/fuchsia-test-runner.py start \ - --rust-build ${RUST_SRC_PATH}/build \ - --sdk ${SDK_PATH} \ - --target {x86_64-unknown-fuchsia|aarch64-unknown-fuchsia} \ - --verbose \ + source config-env.sh && \ + src/ci/docker/scripts/fuchsia-test-runner.py start \ + --rust-build ${RUST_SRC_PATH}/build \ + --sdk ${SDK_PATH} \ + --target {x86_64-unknown-fuchsia|aarch64-unknown-fuchsia|riscv64gc-unknown-fuchsia} \ + --verbose \ ) ``` @@ -707,7 +719,7 @@ run the full `tests/ui` test suite: ( \ source config-env.sh && \ ./x.py \ - --config bootstrap.toml \ + --config bootstrap.toml \ --stage=2 \ test tests/ui \ --target x86_64-unknown-fuchsia \ From 225a061aa5bd10b4e56f8a80cfe4686297d3ff57 Mon Sep 17 00:00:00 2001 From: Max Dexheimer Date: Tue, 18 Aug 2026 08:41:23 +0200 Subject: [PATCH 20/29] Implement arbitrary casts in custom mir --- .../src/builder/custom/parse/instruction.rs | 97 +++++++++++++++++++ compiler/rustc_span/src/symbol.rs | 25 +++++ library/core/src/intrinsics/mir.rs | 35 +++++++ .../mir-opt/building/custom/arbitrary_cast.rs | 80 +++++++++++++++ 4 files changed, 237 insertions(+) create mode 100644 tests/mir-opt/building/custom/arbitrary_cast.rs diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index 84203c5caefea..5454a7bef67a7 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -1,8 +1,10 @@ use rustc_abi::{FieldIdx, VariantIdx}; +use rustc_hir::Safety; use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty; +use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::cast::mir_cast_kind; use rustc_span::{Span, Spanned}; @@ -205,6 +207,97 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { ) } + fn parse_cast_fn_ptr_safety(&self, expr_id: ExprId) -> PResult { + parse_by_kind!(self, expr_id, _, "function pointer safety", + @variant(mir_cast_fn_ptr_safety, Safe) => { + Ok(Safety::Safe) + }, + @variant(mir_cast_fn_ptr_safety, Unsafe) => { + Ok(Safety::Unsafe) + }, + ) + } + + fn parse_cast_pointer_coercion(&self, expr_id: ExprId) -> PResult { + parse_by_kind!(self, expr_id, expr, "pointer coercion kind", + @variant(mir_cast_ptr_coercion, ReifyFnPointer) => { + let ExprKind::Adt(AdtExpr { fields, .. }) = &expr.kind else { + unreachable!("already matched") + }; + Ok(PointerCoercion::ReifyFnPointer( + self.parse_cast_fn_ptr_safety(fields[0].expr)?, + )) + }, + @variant(mir_cast_ptr_coercion, UnsafeFnPointer) => { + Ok(PointerCoercion::UnsafeFnPointer) + }, + @variant(mir_cast_ptr_coercion, ClosureFnPointer) => { + let ExprKind::Adt(AdtExpr { fields, .. }) = &expr.kind else { + unreachable!("already matched") + }; + Ok(PointerCoercion::ClosureFnPointer( + self.parse_cast_fn_ptr_safety(fields[0].expr)?, + )) + }, + @variant(mir_cast_ptr_coercion, MutToConstPointer) => { + Ok(PointerCoercion::MutToConstPointer) + }, + @variant(mir_cast_ptr_coercion, ArrayToPointer) => { + Ok(PointerCoercion::ArrayToPointer) + }, + @variant(mir_cast_ptr_coercion, UnsizePointee) => { + Ok(PointerCoercion::Unsize) + }, + ) + } + + fn parse_cast_kind(&self, expr_id: ExprId) -> PResult { + parse_by_kind!(self, expr_id, expr, "cast kind", + @variant(mir_cast_kind, PointerExposeProvenance) => { + Ok(CastKind::PointerExposeProvenance) + }, + @variant(mir_cast_kind, PointerWithExposedProvenance) => { + Ok(CastKind::PointerWithExposedProvenance) + }, + @variant(mir_cast_kind, IntToInt) => { + Ok(CastKind::IntToInt) + }, + @variant(mir_cast_kind, FloatToInt) => { + Ok(CastKind::FloatToInt) + }, + @variant(mir_cast_kind, FloatToFloat) => { + Ok(CastKind::FloatToFloat) + }, + @variant(mir_cast_kind, IntToFloat) => { + Ok(CastKind::IntToFloat) + }, + @variant(mir_cast_kind, PtrToPtr) => { + Ok(CastKind::PtrToPtr) + }, + @variant(mir_cast_kind, FnPtrToPtr) => { + Ok(CastKind::FnPtrToPtr) + }, + @variant(mir_cast_kind, Transmute) => { + Ok(CastKind::Transmute) + }, + @variant(mir_cast_kind, BoxDerefTransmute) => { + Ok(CastKind::BoxDerefTransmute) + }, + @variant(mir_cast_kind, Subtype) => { + Ok(CastKind::Subtype) + }, + @variant(mir_cast_kind, PointerCoercion) => { + let ExprKind::Adt(AdtExpr { fields, .. }) = &expr.kind else { + unreachable!("already matched") + }; + Ok(CastKind::PointerCoercion( + self.parse_cast_pointer_coercion(fields[0].expr)?, + CoercionSource::AsCast, + )) + }, + ) + } + fn parse_rvalue(&self, expr_id: ExprId) -> PResult> { parse_by_kind!(self, expr_id, expr, "rvalue", @call(mir_discriminant, args) => self.parse_place(args[0]).map(Rvalue::Discriminant), @@ -221,6 +314,10 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { let kind = CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, CoercionSource::AsCast); Ok(Rvalue::Cast(kind, source, expr.ty)) }, + @call(mir_cast, args) => { + let source = self.parse_operand(args[0])?; + Ok(Rvalue::Cast(self.parse_cast_kind(args[1])?, source, expr.ty)) + }, @call(mir_checked, args) => { parse_by_kind!(self, args[0], _, "binary op", ExprKind::Binary { op, lhs, rhs } => { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 17ffb52f4b333..871d5aa97e94e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -163,6 +163,7 @@ symbols! { Arc, ArcWeak, Array, + ArrayToPointer, AsMut, AsRef, AssertParamIsClone, @@ -176,6 +177,7 @@ symbols! { Bool, Borrow, BorrowMut, + BoxDerefTransmute, Break, BuildHasher, CStr, @@ -187,6 +189,7 @@ symbols! { Cleanup, Client, Clone, + ClosureFnPointer, CoercePointee, CoercePointeeValidated, CoerceShared, @@ -219,11 +222,14 @@ symbols! { ExternC, ExternRust, Float, + FloatToFloat, + FloatToInt, FmtArgumentsNew, Fn, FnMut, FnOnce, FnPtr, + FnPtrToPtr, Formatter, Forward, Found, @@ -239,6 +245,8 @@ symbols! { IndexOutput, Input, Int, + IntToFloat, + IntToInt, Into, IntoAsyncIterator, IntoFuture, @@ -255,6 +263,7 @@ symbols! { Lifetime, LintPass, LocalKey, + MutToConstPointer, Mutex, MutexGuard, Named, @@ -274,7 +283,11 @@ symbols! { PinDerefMutHelper, PinMacroHelper, Pointer, + PointerCoercion, + PointerExposeProvenance, + PointerWithExposedProvenance, Poll, + PtrToPtr, Range, RangeCopy, RangeFrom, @@ -294,6 +307,7 @@ symbols! { Reborrow, RefCell, Reference, + ReifyFnPointer, Relaxed, Release, Result, @@ -306,6 +320,8 @@ symbols! { RwLock, RwLockReadGuard, RwLockWriteGuard, + Safe, + Safety, SelfTy, Send, SeqCst, @@ -320,12 +336,14 @@ symbols! { String, Struct, StructuralPartialEq, + Subtype, SymbolIntern, Sync, SyncUnsafeCell, Target, This, TokenStream, + Transmute, TrivialClone, Try, TryCaptureGeneric, @@ -339,7 +357,10 @@ symbols! { Type, Union, Unresolved, + Unsafe, + UnsafeFnPointer, Unsize, + UnsizePointee, Vec, Wrapper, _DECLS, @@ -1321,6 +1342,10 @@ symbols! { mir_assume, mir_basic_block, mir_call, + mir_cast, + mir_cast_fn_ptr_safety, + mir_cast_kind, + mir_cast_ptr_coercion, mir_cast_ptr_to_ptr, mir_cast_transmute, mir_cast_unsize, diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index dce7bf681a7af..929e56872674d 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -508,6 +508,41 @@ define!( fn __debuginfo(name: &'static str, s: T) ); +#[rustc_diagnostic_item = "mir_cast_fn_ptr_safety"] +pub enum Safety { + Safe, + Unsafe, +} +#[rustc_diagnostic_item = "mir_cast_ptr_coercion"] +pub enum PointerCoercion { + ReifyFnPointer(Safety), + UnsafeFnPointer, + ClosureFnPointer(Safety), + MutToConstPointer, + ArrayToPointer, + UnsizePointee, +} +#[rustc_diagnostic_item = "mir_cast_kind"] +pub enum CastKind { + PointerExposeProvenance, + PointerWithExposedProvenance, + IntToInt, + FloatToInt, + FloatToFloat, + IntToFloat, + PtrToPtr, + FnPtrToPtr, + Transmute, + BoxDerefTransmute, + Subtype, + PointerCoercion(PointerCoercion), +} +define!( + "mir_cast", + /// Emits a cast of the specified kind. + fn Cast(operand: T, kind: CastKind) -> U +); + /// Macro for generating custom MIR. /// /// See the module documentation for syntax details. This macro is not magic - it only transforms diff --git a/tests/mir-opt/building/custom/arbitrary_cast.rs b/tests/mir-opt/building/custom/arbitrary_cast.rs new file mode 100644 index 0000000000000..56e6373756b53 --- /dev/null +++ b/tests/mir-opt/building/custom/arbitrary_cast.rs @@ -0,0 +1,80 @@ +//@ skip-filecheck +#![feature(custom_mir, core_intrinsics)] + +extern crate core; +use core::intrinsics::mir::*; + +fn f(x: i32) -> i32 { + x +} + +#[custom_mir(dialect = "built")] +fn reify_fn_ptr() -> fn(i32) -> i32 { + mir! { + { + RET = Cast( + f, + CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer(Safety::Safe)), + ); + Return() + } + } +} + +#[custom_mir(dialect = "built")] +fn fn_ptr_to_unsafe(f: fn()) -> unsafe fn() { + mir! { + { + RET = Cast( + f, + CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer), + ); + Return() + } + } +} + +#[custom_mir(dialect = "runtime")] +fn subtype_fn_ptr(f: fn(&i32)) -> fn(&'static i32) { + mir! { + { + RET = Cast::(f, CastKind::Subtype); + Return() + } + } +} + +#[custom_mir(dialect = "built")] +fn expose_ptr(p: *const i32) -> usize { + mir! { + { + RET = Cast(p, CastKind::PointerExposeProvenance); + Return() + } + } +} + +#[custom_mir(dialect = "built")] +fn ptr_from_exposed(p: usize) -> *const i32 { + mir! { + { + RET = Cast(p, CastKind::PointerWithExposedProvenance); + Return() + } + } +} + +fn main() { + assert_eq!(reify_fn_ptr(), f as fn(i32) -> i32); + + let fn_ptr: fn() = || {}; + assert_eq!(fn_ptr as unsafe fn(), fn_ptr_to_unsafe(fn_ptr)); + + let fn_ptr: fn(&i32) = |_| {}; + assert_eq!(fn_ptr as fn(&'static i32), subtype_fn_ptr(fn_ptr)); + + let p = &1; + assert_eq!(p as *const i32 as usize, expose_ptr(p)); + + assert_eq!(ptr_from_exposed(1), 1 as *const i32); +} From 676862daf62785e9aa0a614f91ce5683c66ccd25 Mon Sep 17 00:00:00 2001 From: Max Dexheimer Date: Thu, 10 Sep 2026 18:00:21 +0200 Subject: [PATCH 21/29] Add extra linebreak to weird test --- tests/ui/hygiene/unpretty-debug-lifetimes.stdout | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/hygiene/unpretty-debug-lifetimes.stdout b/tests/ui/hygiene/unpretty-debug-lifetimes.stdout index 689453326c0b5..c75cc7b2179d3 100644 --- a/tests/ui/hygiene/unpretty-debug-lifetimes.stdout +++ b/tests/ui/hygiene/unpretty-debug-lifetimes.stdout @@ -15,8 +15,8 @@ macro lifetime_hygiene /* 0#0 */ { - ($f /* 0#0 */:ident /* 0#0 */<$a /* 0#0 */:lifetime /* 0#0 */>) - => + ($f /* 0#0 */:ident /* 0#0 */<$a /* 0#0 */:lifetime /* 0#0 + */>) => { fn /* 0#0 */ $f /* 0#0 */<$a /* 0#0 */, 'a /* 0#0 */>() {} } } fn f /* 0#0 */<'a /* 0#0 */, 'a /* 0#1 */>() {} From 15d08109c4ab3414ad761aba86f61e59566d8092 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Wed, 9 Sep 2026 16:04:34 +0100 Subject: [PATCH 22/29] split `macroless_generic_const_args` in two --- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_feature/src/unstable.rs | 4 + compiler/rustc_span/src/symbol.rs | 1 + ...macroless-const-item-generic-const-args.md | 74 +++++++++++++++++++ .../macroless-generic-const-args.md | 6 +- ...onst-pattern-field-type-mismatch-162394.rs | 1 + ...-pattern-field-type-mismatch-162394.stderr | 2 +- .../gca/non-type-equality-ok.rs | 1 + ...st_item_generic_const_args.macroful.stderr | 11 +++ ...macroless_const_item_generic_const_args.rs | 28 +++++++ 10 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/macroless-const-item-generic-const-args.md create mode 100644 tests/ui/feature-gates/feature-gate-macroless_const_item_generic_const_args.macroful.stderr create mode 100644 tests/ui/feature-gates/feature-gate-macroless_const_item_generic_const_args.rs diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a27dc47bf27c3..09ef6abeb3e96 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2685,7 +2685,7 @@ impl<'hir> LoweringContext<'_, 'hir> { match (body, kind) { (body, ConstItemKind::Body) => { let is_direct = |body| { - if self.tcx.features().macroless_generic_const_args() { + if self.tcx.features().macroless_const_item_generic_const_args() { self.can_lower_expr_to_const_arg_direct( body, DirectConstArgContext::MacrolessMinGenericConstArgs, diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index ca70389815141..7d495b3262b04 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -603,6 +603,9 @@ declare_features! ( (unstable, macro_metavar_expr, "1.61.0", Some(83527)), /// Provides a way to concatenate identifiers using metavariable expressions. (unstable, macro_metavar_expr_concat, "1.81.0", Some(124225)), + /// Allows directly represented generic_const_args as the rhs of const items without the + /// `direct_const_arg!` macro. + (incomplete, macroless_const_item_generic_const_args, "CURRENT_RUSTC_VERSION", Some(162540)), /// Allows directly represented generic_const_args without the `direct_const_arg!` macro. (incomplete, macroless_generic_const_args, "1.99.0", Some(159006)), /// Allows `#[marker]` on certain traits allowing overlapping implementations. @@ -854,5 +857,6 @@ pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = &[ pub const DEPENDENT_FEATURES: &[(Symbol, &[Symbol])] = &[ (sym::generic_const_args, &[sym::min_generic_const_args]), (sym::macroless_generic_const_args, &[sym::min_generic_const_args]), + (sym::macroless_const_item_generic_const_args, &[sym::min_generic_const_args]), (sym::unsized_const_params, &[sym::adt_const_params]), ]; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c8fa04e08f768..f3135fefe8dbe 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1252,6 +1252,7 @@ symbols! { macro_reexport, macro_use, macro_vis_matcher, + macroless_const_item_generic_const_args, macroless_generic_const_args, macros_in_extern, main, diff --git a/src/doc/unstable-book/src/language-features/macroless-const-item-generic-const-args.md b/src/doc/unstable-book/src/language-features/macroless-const-item-generic-const-args.md new file mode 100644 index 0000000000000..d208d3243229d --- /dev/null +++ b/src/doc/unstable-book/src/language-features/macroless-const-item-generic-const-args.md @@ -0,0 +1,74 @@ +# macroless_generic_const_args + +Enables implementing const items under `#![feature(min_generic_const_args)]` and `#![feature(generic_const_args)]` without the `direct_const_arg!` macro. + +The tracking issue for this feature is: [#162540] + +[#162540]: https://github.com/rust-lang/rust/issues/162540 + +------------------------ + +Warning: This feature is incomplete; its design and syntax may change. + +Related features: +- [min_generic_const_args]. See that doc for what the `direct_const_arg!` is. This feature enables +support for directly represented const arguments as the rhs of const items without the macro. +- [macroless_generic_const_args]. For a version of this feature that works for const arguments in other +positions + +[min_generic_const_args]: min-generic-const-args.md +[macroless_generic_const_args]: macroless-generic-const-args.md + +## Examples + +Here is an example from [min_generic_const_args]: + +[min_generic_const_args]: min-generic-const-args.md + +```rust,ignore (needs new solver) +#![allow(incomplete_features)] +#![feature( + min_generic_const_args, + generic_const_args, + macroless_generic_const_args, + generic_const_items, +)] + +trait Trait { + const ASSOC: usize; +} + +impl Trait for () { + const ASSOC: usize = core::direct_const_arg!(N); +} + +fn foo() { + let a: [(); <() as Trait>::ASSOC::] + = [(); N]; +} +``` + +Using `#![feature(macroless_const_item_generic_const_args)]` enables you to write the above without the macro: + +```rust,ignore (needs new solver) +#![allow(incomplete_features)] +#![feature( + min_generic_const_args, + generic_const_args, + macroless_generic_const_args, + generic_const_items, +)] + +trait Trait { + const ASSOC: usize; +} + +impl Trait for () { + const ASSOC: usize = N; +} + +fn foo() { + let a: [(); <() as Trait>::ASSOC::] + = [(); N]; +} +``` diff --git a/src/doc/unstable-book/src/language-features/macroless-generic-const-args.md b/src/doc/unstable-book/src/language-features/macroless-generic-const-args.md index 18f4e5cd97a98..6b1205a006d0f 100644 --- a/src/doc/unstable-book/src/language-features/macroless-generic-const-args.md +++ b/src/doc/unstable-book/src/language-features/macroless-generic-const-args.md @@ -10,10 +10,14 @@ The tracking issue for this feature is: [#159006] Warning: This feature is incomplete; its design and syntax may change. -Related features: [min_generic_const_args]. See that doc for what the `direct_const_arg!` is. This feature enables +Related features: +- [min_generic_const_args]. See that doc for what the `direct_const_arg!` is. This feature enables support for directly represented const arguments without the macro. +- [macroless_const_item_generic_const_args]. For a version of this feature that works for const arguments +as the right hand side of a const item. [min_generic_const_args]: min-generic-const-args.md +[macroless_const_item_generic_const_args]: macroless-const-item-generic-const-args.md ## Examples diff --git a/tests/ui/const-generics/gca/const-pattern-field-type-mismatch-162394.rs b/tests/ui/const-generics/gca/const-pattern-field-type-mismatch-162394.rs index 9557c9da80702..181693c365255 100644 --- a/tests/ui/const-generics/gca/const-pattern-field-type-mismatch-162394.rs +++ b/tests/ui/const-generics/gca/const-pattern-field-type-mismatch-162394.rs @@ -2,6 +2,7 @@ #![allow(incomplete_features)] #![feature(macroless_generic_const_args)] +#![feature(macroless_const_item_generic_const_args)] #![feature(generic_const_args, min_generic_const_args)] #![feature(min_adt_const_params)] diff --git a/tests/ui/const-generics/gca/const-pattern-field-type-mismatch-162394.stderr b/tests/ui/const-generics/gca/const-pattern-field-type-mismatch-162394.stderr index afa00eaeed7e7..9dd229cc46a34 100644 --- a/tests/ui/const-generics/gca/const-pattern-field-type-mismatch-162394.stderr +++ b/tests/ui/const-generics/gca/const-pattern-field-type-mismatch-162394.stderr @@ -1,5 +1,5 @@ error: the constant `"foo"` is not of type `()` - --> $DIR/const-pattern-field-type-mismatch-162394.rs:16:5 + --> $DIR/const-pattern-field-type-mismatch-162394.rs:17:5 | LL | const A2: Foo = Self::FooA("foo"); | ^^^^^^^^^^^^^ expected `()`, found `&'static str` diff --git a/tests/ui/const-generics/gca/non-type-equality-ok.rs b/tests/ui/const-generics/gca/non-type-equality-ok.rs index 45dcef1f2dc00..ae7c069ea55f5 100644 --- a/tests/ui/const-generics/gca/non-type-equality-ok.rs +++ b/tests/ui/const-generics/gca/non-type-equality-ok.rs @@ -4,6 +4,7 @@ #![feature( min_generic_const_args, macroless_generic_const_args, + macroless_const_item_generic_const_args, generic_const_args, generic_const_items )] diff --git a/tests/ui/feature-gates/feature-gate-macroless_const_item_generic_const_args.macroful.stderr b/tests/ui/feature-gates/feature-gate-macroless_const_item_generic_const_args.macroful.stderr new file mode 100644 index 0000000000000..d49f65acd5a0e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-macroless_const_item_generic_const_args.macroful.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/feature-gate-macroless_const_item_generic_const_args.rs:24:11 + | +LL | let a: [(); <() as Trait>::ASSOC::] + | ------------------------------- expected due to this +LL | = [(); N]; + | ^^^^^^^ expected an array with a size of <() as Trait>::ASSOC::, found one with a size of N + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/feature-gates/feature-gate-macroless_const_item_generic_const_args.rs b/tests/ui/feature-gates/feature-gate-macroless_const_item_generic_const_args.rs new file mode 100644 index 0000000000000..a967dffcd39af --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-macroless_const_item_generic_const_args.rs @@ -0,0 +1,28 @@ +//@ revisions: macroless macroful +//@[macroless] check-pass +//@ compile-flags: -Znext-solver + +#![feature( + min_generic_const_args, + generic_const_args, + macroless_generic_const_args, + generic_const_items, +)] + +#![cfg_attr(macroless, feature(macroless_const_item_generic_const_args))] + +trait Trait { + const ASSOC: usize; +} + +impl Trait for () { + const ASSOC: usize = N; +} + +fn foo() { + let a: [(); <() as Trait>::ASSOC::] + = [(); N]; + //[macroful]~^ ERROR: mismatched types +} + +fn main() {} From 2319a0c050b8efdb7c451eeb4d855c7d97f8831f Mon Sep 17 00:00:00 2001 From: malezjaa Date: Fri, 11 Sep 2026 09:03:15 +0200 Subject: [PATCH 23/29] regression test for opaque field projection in closure capture --- .../migrations/opaque-field-projection.rs | 15 +++++++++++++++ .../migrations/opaque-field-projection.stderr | 14 ++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/ui/closures/2229_closure_analysis/migrations/opaque-field-projection.rs create mode 100644 tests/ui/closures/2229_closure_analysis/migrations/opaque-field-projection.stderr diff --git a/tests/ui/closures/2229_closure_analysis/migrations/opaque-field-projection.rs b/tests/ui/closures/2229_closure_analysis/migrations/opaque-field-projection.rs new file mode 100644 index 0000000000000..4ae2079a58255 --- /dev/null +++ b/tests/ui/closures/2229_closure_analysis/migrations/opaque-field-projection.rs @@ -0,0 +1,15 @@ +//! Regression test for: https://github.com/rust-lang/rust/issues/156837 +//@ compile-flags: -Znext-solver=globally --crate-type=lib +//@ edition: 2018 + +#![warn(rust_2021_incompatible_closure_captures)] + +async fn get() {} + +fn check() { + let mut v = get(); + (|| match v { + (1, _) => (), + //~^ ERROR mismatched types + })() +} diff --git a/tests/ui/closures/2229_closure_analysis/migrations/opaque-field-projection.stderr b/tests/ui/closures/2229_closure_analysis/migrations/opaque-field-projection.stderr new file mode 100644 index 0000000000000..c40d44e1a6dbc --- /dev/null +++ b/tests/ui/closures/2229_closure_analysis/migrations/opaque-field-projection.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/opaque-field-projection.rs:12:9 + | +LL | (|| match v { + | - this expression has type `impl Future` +LL | (1, _) => (), + | ^^^^^^ expected future, found `(_, _)` + | + = note: expected opaque type `impl Future` + found tuple `(_, _)` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. From ad8967754d755aac9aea1589c5ece5707a36bb84 Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 25 Mar 2026 22:51:43 +0800 Subject: [PATCH 24/29] Skip linting unused braces for FunctionArg and MethodArg context for 2024 edition --- compiler/rustc_lint/src/unused.rs | 83 +++++ .../mgca/bad-direct-const-arg.rs | 9 +- .../mgca/bad-direct-const-arg.stderr | 12 +- .../ui/lint/unused_braces-issue-154247.fixed | 167 +++++++++ tests/ui/lint/unused_braces-issue-154247.rs | 167 +++++++++ .../ui/lint/unused_braces-issue-154247.stderr | 319 ++++++++++++++++++ 6 files changed, 753 insertions(+), 4 deletions(-) create mode 100644 tests/ui/lint/unused_braces-issue-154247.fixed create mode 100644 tests/ui/lint/unused_braces-issue-154247.rs create mode 100644 tests/ui/lint/unused_braces-issue-154247.stderr diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 1ff2a2cb1a404..7452e3e08ade9 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -135,6 +135,88 @@ trait UnusedDelimLint { is_kw: bool, ); + /// Returns whether the outer braces of a single-expression function/method + /// argument block can be removed. + /// + /// In Rust 2024, `{ expr }` can drop tail-expression temporaries before the + /// call starts. Removing the block may extend those temporaries, so lint only + /// expression forms that are harmless here. + fn expr_allows_remove_arg_block(expr: &ast::Expr) -> bool { + use ast::ExprKind::*; + + match &expr.peel_parens().kind { + Lit(_) | IncludedBytes(_) | Path(..) => true, + Unary(_, expr) + | Cast(expr, _) + | Type(expr, _) + | Use(expr, _) + | Await(expr, _) + | Try(expr) + | Move(expr, _) + | AddrOf(_, _, expr) + | UnsafeBinderCast(_, expr, _) => Self::expr_allows_remove_arg_block(expr), + Array(exprs) | Tup(exprs) => { + exprs.iter().all(|expr| Self::expr_allows_remove_arg_block(expr)) + } + Binary(_, lhs, rhs) | Assign(lhs, rhs, _) | AssignOp(_, lhs, rhs) => { + Self::expr_allows_remove_arg_block(lhs) && Self::expr_allows_remove_arg_block(rhs) + } + Index(base, index, _) => { + Self::expr_allows_remove_arg_block(base) + && Self::expr_allows_remove_arg_block(index) + } + Range(start, end, _) => { + start.as_ref().is_none_or(|expr| Self::expr_allows_remove_arg_block(expr)) + && end.as_ref().is_none_or(|expr| Self::expr_allows_remove_arg_block(expr)) + } + Struct(expr) => { + expr.fields.iter().all(|field| Self::expr_allows_remove_arg_block(&field.expr)) + && match &expr.rest { + ast::StructRest::Base(expr) => Self::expr_allows_remove_arg_block(expr), + ast::StructRest::Rest(_) | ast::StructRest::None => true, + ast::StructRest::NoneWithError(_) => false, + } + } + Repeat(expr, _) => Self::expr_allows_remove_arg_block(expr), + ConstBlock(_) + | If(..) + | While(..) + | ForLoop { .. } + | Loop(..) + | Match(..) + | Closure(_) + | Block(..) + | Gen(..) + | TryBlock(..) + | Break(..) + | Continue(_) + | Ret(_) + | InlineAsm(_) + | OffsetOf(..) + | Yield(_) + | Yeet(_) + | Paren(_) + | Become(_) => true, + Call(..) | MethodCall(_) | Let(..) | Field(..) | MacCall(_) | FormatArgs(_) => false, + // `direct_const_arg!()` is invalid in function/method argument position. + DirectConstArg(_) => false, + // don't lint for placeholder/error-recovery + Underscore | Err(_) | Dummy => false, + } + } + + /// Returns whether `{ expr }` must be kept in function/method argument + /// position to avoid changing temporary lifetime semantics. + fn needs_arg_block_to_preserve_temporaries( + ctx: UnusedDelimsCtx, + arg_block: &ast::Expr, + expr: &ast::Expr, + ) -> bool { + matches!(ctx, UnusedDelimsCtx::FunctionArg | UnusedDelimsCtx::MethodArg) + && arg_block.span.edition().at_least_rust_2024() + && !Self::expr_allows_remove_arg_block(expr) + } + fn is_expr_delims_necessary( inner: &ast::Expr, ctx: UnusedDelimsCtx, @@ -1098,6 +1180,7 @@ impl UnusedDelimLint for UnusedBraces { // lock guard, before the loop starts. && !(ctx == UnusedDelimsCtx::ForIterExpr && value.span.edition().at_least_rust_2024()) + && !Self::needs_arg_block_to_preserve_temporaries(ctx, value, expr) && (ctx != UnusedDelimsCtx::AnonConst || (matches!(expr.kind, ast::ExprKind::Lit(_)) && !expr.span.from_expansion())) diff --git a/tests/ui/const-generics/mgca/bad-direct-const-arg.rs b/tests/ui/const-generics/mgca/bad-direct-const-arg.rs index 451806ca6e1db..59fdccf29b7b5 100644 --- a/tests/ui/const-generics/mgca/bad-direct-const-arg.rs +++ b/tests/ui/const-generics/mgca/bad-direct-const-arg.rs @@ -1,8 +1,15 @@ -//! Simple error message test, nothing special here +//@ edition: 2024 + +//! Reject direct const arguments in value/type positions without unrelated brace suggestions. #![feature(min_generic_const_args)] +#![deny(unused_braces)] fn main(x: core::direct_const_arg!(2)) { //~^ ERROR expected type, found `direct_const_arg!()` constant let _ = core::direct_const_arg!(2); //~^ ERROR expected expression, found `direct_const_arg!()` constant + consume({ core::direct_const_arg!(2) }); + //~^ ERROR expected expression, found `direct_const_arg!()` constant } + +fn consume(_: usize) {} diff --git a/tests/ui/const-generics/mgca/bad-direct-const-arg.stderr b/tests/ui/const-generics/mgca/bad-direct-const-arg.stderr index b77791ad5b3ee..d54a2c4400ea7 100644 --- a/tests/ui/const-generics/mgca/bad-direct-const-arg.stderr +++ b/tests/ui/const-generics/mgca/bad-direct-const-arg.stderr @@ -1,14 +1,20 @@ error: expected expression, found `direct_const_arg!()` constant - --> $DIR/bad-direct-const-arg.rs:6:13 + --> $DIR/bad-direct-const-arg.rs:9:13 | LL | let _ = core::direct_const_arg!(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: expected expression, found `direct_const_arg!()` constant + --> $DIR/bad-direct-const-arg.rs:11:15 + | +LL | consume({ core::direct_const_arg!(2) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: expected type, found `direct_const_arg!()` constant - --> $DIR/bad-direct-const-arg.rs:4:12 + --> $DIR/bad-direct-const-arg.rs:7:12 | LL | fn main(x: core::direct_const_arg!(2)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/lint/unused_braces-issue-154247.fixed b/tests/ui/lint/unused_braces-issue-154247.fixed new file mode 100644 index 0000000000000..08c8999611eb9 --- /dev/null +++ b/tests/ui/lint/unused_braces-issue-154247.fixed @@ -0,0 +1,167 @@ +//@ edition: 2024 +//@ check-pass +//@ run-rustfix + +#![feature(move_expr)] +#![warn(unused_braces)] + +use std::sync::Mutex; + +fn consume(lock: &Mutex>, _value: usize) { + let _guard = lock.lock().unwrap(); +} + +fn consume_int(_: T) {} + +fn make_int() -> usize { + 7 +} + +fn static_int_ref() -> &'static usize { + &7 +} + +struct Point { + _x: usize, +} + +struct Pair { + _x: usize, + _y: usize, +} + +fn make_pair() -> Pair { + Pair { _x: 1, _y: 2 } +} + +macro_rules! make_int_macro { + () => { + make_int() + }; +} + +struct Lockable(Mutex>); + +impl Lockable { + fn update(&self, _value: usize) { + let _guard = self.0.lock().unwrap(); + } + + fn run(&self) { + // These blocks shorten the lifetime of the temporary `MutexGuard`. + consume(&self.0, { self.0.lock().unwrap().len() }); + self.update({ self.0.lock().unwrap().len() }); + consume_int({ [self.0.lock().unwrap().len()] }); + } +} + +fn main() { + let x = 7; + + consume_int(7); + //~^ WARN unnecessary braces + + consume_int(x); + //~^ WARN unnecessary braces + + consume_int(x as usize); + //~^ WARN unnecessary braces + + consume_int((x, 7)); + //~^ WARN unnecessary braces + + consume_int([x, 7]); + //~^ WARN unnecessary braces + + consume_int(!false); + //~^ WARN unnecessary braces + + consume_int(x + 1); + //~^ WARN unnecessary braces + + consume_int([x, 7][0]); + //~^ WARN unnecessary braces + + consume_int(0..x); + //~^ WARN unnecessary braces + + consume_int(const { 7 }); + //~^ WARN unnecessary braces + + consume_int(if x > 0 { x } else { 0 }); + //~^ WARN unnecessary braces + + consume_int(while false {}); + //~^ WARN unnecessary braces + + consume_int(for _ in 0..0 {}); + //~^ WARN unnecessary braces + + consume_int(loop { break x; }); + //~^ WARN unnecessary braces + + consume_int(match x { 0 => 1, _ => x }); + //~^ WARN unnecessary braces + + consume_int(x); + //~^ WARN unnecessary braces + //~| WARN unnecessary braces + + consume_int(|| x); + //~^ WARN unnecessary braces + + let mut y = x; + + consume_int(y += 1); + //~^ WARN unnecessary braces + + consume_int(y); + + consume_int(y = x); + //~^ WARN unnecessary braces + + consume_int(y); + + consume_int(Point { _x: x }); + //~^ WARN unnecessary braces + + consume_int([x; 2]); + //~^ WARN unnecessary braces + + consume_int(&x); + //~^ WARN unnecessary braces + + let move_expr_closure = || { + consume_int(move(x)); + //~^ WARN unnecessary braces + + consume_int({ move(make_int()) }); + }; + move_expr_closure(); + + Lockable(Mutex::new(vec![1])).update(7); + //~^ WARN unnecessary braces + + Lockable(Mutex::new(vec![1])).update(x as usize); + //~^ WARN unnecessary braces + + Lockable(Mutex::new(vec![1])).run(); + + // These blocks contain calls, borrows, macros, or projections where removing + // the argument block may extend temporaries in Rust 2024. + consume_int({ make_int() }); + consume_int({ make_int() + 1 }); + consume_int({ String::from("abc").len() }); + consume_int({ [make_int(), x] }); + consume_int({ [x, make_int()][0] }); + consume_int({ 0..make_int() }); + consume_int({ Point { _x: make_int() } }); + consume_int({ Pair { _x: x, ..make_pair() } }); + consume_int({ [make_int(); 2] }); + consume_int({ make_int_macro!() }); + consume_int({ format_args!("value") }); + consume_int({ &*static_int_ref() }); + + let point = Point { _x: x }; + consume_int({ point._x }); +} diff --git a/tests/ui/lint/unused_braces-issue-154247.rs b/tests/ui/lint/unused_braces-issue-154247.rs new file mode 100644 index 0000000000000..6d2f28c4d5a2b --- /dev/null +++ b/tests/ui/lint/unused_braces-issue-154247.rs @@ -0,0 +1,167 @@ +//@ edition: 2024 +//@ check-pass +//@ run-rustfix + +#![feature(move_expr)] +#![warn(unused_braces)] + +use std::sync::Mutex; + +fn consume(lock: &Mutex>, _value: usize) { + let _guard = lock.lock().unwrap(); +} + +fn consume_int(_: T) {} + +fn make_int() -> usize { + 7 +} + +fn static_int_ref() -> &'static usize { + &7 +} + +struct Point { + _x: usize, +} + +struct Pair { + _x: usize, + _y: usize, +} + +fn make_pair() -> Pair { + Pair { _x: 1, _y: 2 } +} + +macro_rules! make_int_macro { + () => { + make_int() + }; +} + +struct Lockable(Mutex>); + +impl Lockable { + fn update(&self, _value: usize) { + let _guard = self.0.lock().unwrap(); + } + + fn run(&self) { + // These blocks shorten the lifetime of the temporary `MutexGuard`. + consume(&self.0, { self.0.lock().unwrap().len() }); + self.update({ self.0.lock().unwrap().len() }); + consume_int({ [self.0.lock().unwrap().len()] }); + } +} + +fn main() { + let x = 7; + + consume_int({ 7 }); + //~^ WARN unnecessary braces + + consume_int({ x }); + //~^ WARN unnecessary braces + + consume_int({ x as usize }); + //~^ WARN unnecessary braces + + consume_int({ (x, 7) }); + //~^ WARN unnecessary braces + + consume_int({ [x, 7] }); + //~^ WARN unnecessary braces + + consume_int({ !false }); + //~^ WARN unnecessary braces + + consume_int({ x + 1 }); + //~^ WARN unnecessary braces + + consume_int({ [x, 7][0] }); + //~^ WARN unnecessary braces + + consume_int({ 0..x }); + //~^ WARN unnecessary braces + + consume_int({ const { 7 } }); + //~^ WARN unnecessary braces + + consume_int({ if x > 0 { x } else { 0 } }); + //~^ WARN unnecessary braces + + consume_int({ while false {} }); + //~^ WARN unnecessary braces + + consume_int({ for _ in 0..0 {} }); + //~^ WARN unnecessary braces + + consume_int({ loop { break x; } }); + //~^ WARN unnecessary braces + + consume_int({ match x { 0 => 1, _ => x } }); + //~^ WARN unnecessary braces + + consume_int({ { x } }); + //~^ WARN unnecessary braces + //~| WARN unnecessary braces + + consume_int({ || x }); + //~^ WARN unnecessary braces + + let mut y = x; + + consume_int({ y += 1 }); + //~^ WARN unnecessary braces + + consume_int(y); + + consume_int({ y = x }); + //~^ WARN unnecessary braces + + consume_int(y); + + consume_int({ Point { _x: x } }); + //~^ WARN unnecessary braces + + consume_int({ [x; 2] }); + //~^ WARN unnecessary braces + + consume_int({ &x }); + //~^ WARN unnecessary braces + + let move_expr_closure = || { + consume_int({ move(x) }); + //~^ WARN unnecessary braces + + consume_int({ move(make_int()) }); + }; + move_expr_closure(); + + Lockable(Mutex::new(vec![1])).update({ 7 }); + //~^ WARN unnecessary braces + + Lockable(Mutex::new(vec![1])).update({ x as usize }); + //~^ WARN unnecessary braces + + Lockable(Mutex::new(vec![1])).run(); + + // These blocks contain calls, borrows, macros, or projections where removing + // the argument block may extend temporaries in Rust 2024. + consume_int({ make_int() }); + consume_int({ make_int() + 1 }); + consume_int({ String::from("abc").len() }); + consume_int({ [make_int(), x] }); + consume_int({ [x, make_int()][0] }); + consume_int({ 0..make_int() }); + consume_int({ Point { _x: make_int() } }); + consume_int({ Pair { _x: x, ..make_pair() } }); + consume_int({ [make_int(); 2] }); + consume_int({ make_int_macro!() }); + consume_int({ format_args!("value") }); + consume_int({ &*static_int_ref() }); + + let point = Point { _x: x }; + consume_int({ point._x }); +} diff --git a/tests/ui/lint/unused_braces-issue-154247.stderr b/tests/ui/lint/unused_braces-issue-154247.stderr new file mode 100644 index 0000000000000..5d5fd1c95513a --- /dev/null +++ b/tests/ui/lint/unused_braces-issue-154247.stderr @@ -0,0 +1,319 @@ +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:61:17 + | +LL | consume_int({ 7 }); + | ^^ ^^ + | +note: the lint level is defined here + --> $DIR/unused_braces-issue-154247.rs:6:9 + | +LL | #![warn(unused_braces)] + | ^^^^^^^^^^^^^ +help: remove these braces + | +LL - consume_int({ 7 }); +LL + consume_int(7); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:64:17 + | +LL | consume_int({ x }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ x }); +LL + consume_int(x); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:67:17 + | +LL | consume_int({ x as usize }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ x as usize }); +LL + consume_int(x as usize); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:70:17 + | +LL | consume_int({ (x, 7) }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ (x, 7) }); +LL + consume_int((x, 7)); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:73:17 + | +LL | consume_int({ [x, 7] }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ [x, 7] }); +LL + consume_int([x, 7]); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:76:17 + | +LL | consume_int({ !false }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ !false }); +LL + consume_int(!false); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:79:17 + | +LL | consume_int({ x + 1 }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ x + 1 }); +LL + consume_int(x + 1); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:82:17 + | +LL | consume_int({ [x, 7][0] }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ [x, 7][0] }); +LL + consume_int([x, 7][0]); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:85:17 + | +LL | consume_int({ 0..x }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ 0..x }); +LL + consume_int(0..x); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:88:17 + | +LL | consume_int({ const { 7 } }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ const { 7 } }); +LL + consume_int(const { 7 }); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:91:17 + | +LL | consume_int({ if x > 0 { x } else { 0 } }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ if x > 0 { x } else { 0 } }); +LL + consume_int(if x > 0 { x } else { 0 }); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:94:17 + | +LL | consume_int({ while false {} }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ while false {} }); +LL + consume_int(while false {}); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:97:17 + | +LL | consume_int({ for _ in 0..0 {} }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ for _ in 0..0 {} }); +LL + consume_int(for _ in 0..0 {}); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:100:17 + | +LL | consume_int({ loop { break x; } }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ loop { break x; } }); +LL + consume_int(loop { break x; }); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:103:17 + | +LL | consume_int({ match x { 0 => 1, _ => x } }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ match x { 0 => 1, _ => x } }); +LL + consume_int(match x { 0 => 1, _ => x }); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:106:17 + | +LL | consume_int({ { x } }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ { x } }); +LL + consume_int({ x }); + | + +warning: unnecessary braces around block return value + --> $DIR/unused_braces-issue-154247.rs:106:19 + | +LL | consume_int({ { x } }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ { x } }); +LL + consume_int({ x }); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:110:17 + | +LL | consume_int({ || x }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ || x }); +LL + consume_int(|| x); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:115:17 + | +LL | consume_int({ y += 1 }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ y += 1 }); +LL + consume_int(y += 1); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:120:17 + | +LL | consume_int({ y = x }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ y = x }); +LL + consume_int(y = x); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:125:17 + | +LL | consume_int({ Point { _x: x } }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ Point { _x: x } }); +LL + consume_int(Point { _x: x }); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:128:17 + | +LL | consume_int({ [x; 2] }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ [x; 2] }); +LL + consume_int([x; 2]); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:131:17 + | +LL | consume_int({ &x }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ &x }); +LL + consume_int(&x); + | + +warning: unnecessary braces around function argument + --> $DIR/unused_braces-issue-154247.rs:135:21 + | +LL | consume_int({ move(x) }); + | ^^ ^^ + | +help: remove these braces + | +LL - consume_int({ move(x) }); +LL + consume_int(move(x)); + | + +warning: unnecessary braces around method argument + --> $DIR/unused_braces-issue-154247.rs:142:42 + | +LL | Lockable(Mutex::new(vec![1])).update({ 7 }); + | ^^ ^^ + | +help: remove these braces + | +LL - Lockable(Mutex::new(vec![1])).update({ 7 }); +LL + Lockable(Mutex::new(vec![1])).update(7); + | + +warning: unnecessary braces around method argument + --> $DIR/unused_braces-issue-154247.rs:145:42 + | +LL | Lockable(Mutex::new(vec![1])).update({ x as usize }); + | ^^ ^^ + | +help: remove these braces + | +LL - Lockable(Mutex::new(vec![1])).update({ x as usize }); +LL + Lockable(Mutex::new(vec![1])).update(x as usize); + | + +warning: 26 warnings emitted + From 69afc99f5075b789d4f1b1d6a08b4a114aae4d2e Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Fri, 11 Sep 2026 08:18:39 +0000 Subject: [PATCH 25/29] Refactor `HygieneEncodeContext` * Refactor `HygieneEncodeContext` * Review: remove comment outdated part * Review: return `raw_encode_syntax_context` as a free function * Review: small cleanups * Review: add comment about expansions data `Option` * Review: don't set explicit capacity * Review: return `queued` -> `latest` * Remove not needed changes * Fix `Rc` cloning * Return comment --- compiler/rustc_metadata/src/rmeta/encoder.rs | 21 ++-- compiler/rustc_middle/src/hooks.rs | 2 +- .../rustc_middle/src/query/on_disk_cache.rs | 34 +++--- compiler/rustc_query_impl/src/incremental.rs | 8 +- compiler/rustc_span/src/hygiene.rs | 104 +++++++++++------- 5 files changed, 99 insertions(+), 70 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 713671c3a5b47..ab0f0167b6ef3 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1,8 +1,10 @@ use std::borrow::Borrow; +use std::cell::RefCell; use std::collections::hash_map::Entry; use std::fs::File; use std::io::{Read, Seek, Write}; use std::path::{Path, PathBuf}; +use std::rc::Rc; use std::sync::Arc; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; @@ -29,7 +31,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque}; use rustc_session::config::mitigation_coverage::DeniedPartialMitigation; use rustc_session::config::{OptLevel, TargetModifier}; use rustc_span::def_id::CRATE_MOD_ID; -use rustc_span::hygiene::HygieneEncodeContext; +use rustc_span::hygiene::{HygieneEncodeContext, raw_encode_syntax_context}; use rustc_span::{ ByteSymbol, ExternalSource, FileName, SourceFile, SpanData, SpanEncoder, StableSourceFileId, Symbol, SyntaxContext, sym, @@ -66,7 +68,7 @@ pub(super) struct EncodeContext<'a, 'tcx> { // order of `SourceFiles`, and encoded inside `Span`s. required_source_files: Option>, is_proc_macro: bool, - hygiene_ctxt: &'a HygieneEncodeContext, + hygiene_ctxt: Rc>, // Used for both `Symbol`s and `ByteSymbol`s. symbol_index_table: FxHashMap, } @@ -156,7 +158,7 @@ impl<'a, 'tcx> SpanEncoder for EncodeContext<'a, 'tcx> { } fn encode_syntax_context(&mut self, syntax_context: SyntaxContext) { - rustc_span::hygiene::raw_encode_syntax_context(syntax_context, self.hygiene_ctxt, self); + raw_encode_syntax_context(syntax_context, Rc::clone(&self.hygiene_ctxt), self) } fn encode_expn_id(&mut self, expn_id: ExpnId) { @@ -165,7 +167,7 @@ impl<'a, 'tcx> SpanEncoder for EncodeContext<'a, 'tcx> { // data from the corresponding crate's metadata. // FIXME(#43047) FIXME(#74731) We may eventually want to avoid relying on external // metadata from proc-macro crates. - self.hygiene_ctxt.schedule_expn_data_for_encoding(expn_id); + self.hygiene_ctxt.borrow_mut().schedule_expn_data_for_encoding(expn_id); } expn_id.krate.encode(self); expn_id.local_id.encode(self); @@ -1955,14 +1957,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let mut expn_data_table: TableBuilder<_, _> = Default::default(); let mut expn_hash_table: TableBuilder<_, _> = Default::default(); - self.hygiene_ctxt.encode( + HygieneEncodeContext::encode( + &Rc::clone(&self.hygiene_ctxt), &mut (&mut *self, &mut syntax_contexts, &mut expn_data_table, &mut expn_hash_table), |(this, syntax_contexts, _, _), index, ctxt_data| { syntax_contexts.set_some(index, this.lazy(ctxt_data)); }, |(this, _, expn_data_table, expn_hash_table), index, expn_data, hash| { if let Some(index) = index.as_local() { - expn_data_table.set_some(index.as_raw(), this.lazy(expn_data)); + expn_data_table + .set_some(index.as_raw(), this.lazy(expn_data.expect("local expn"))); + expn_hash_table.set_some(index.as_raw(), this.lazy(hash)); } }, @@ -2548,8 +2553,6 @@ fn with_encode_metadata_header( let required_source_files = Some(FxIndexSet::default()); drop(source_map_files); - let hygiene_ctxt = HygieneEncodeContext::default(); - let mut ecx = EncodeContext { opaque: encoder, tcx, @@ -2563,7 +2566,7 @@ fn with_encode_metadata_header( interpret_allocs: Default::default(), required_source_files, is_proc_macro: tcx.crate_types().contains(&CrateType::ProcMacro), - hygiene_ctxt: &hygiene_ctxt, + hygiene_ctxt: Default::default(), symbol_index_table: Default::default(), }; diff --git a/compiler/rustc_middle/src/hooks.rs b/compiler/rustc_middle/src/hooks.rs index 7a69f58d52fae..df95bd6149e47 100644 --- a/compiler/rustc_middle/src/hooks.rs +++ b/compiler/rustc_middle/src/hooks.rs @@ -106,7 +106,7 @@ declare_hooks! { hook build_mir_inner_impl(def: LocalDefId) -> mir::Body<'tcx>; /// Serializes all eligible query return values into the on-disk cache. - hook encode_query_values(encoder: &mut CacheEncoder<'_, 'tcx>) -> (); + hook encode_query_values(encoder: &mut CacheEncoder<'tcx>) -> (); } #[cold] diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index d743c5dcc7e43..1fa0aa421d584 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -1,4 +1,6 @@ +use std::cell::RefCell; use std::collections::hash_map::Entry; +use std::rc::Rc; use std::sync::Arc; use std::{fmt, mem}; @@ -16,6 +18,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_session::Session; use rustc_span::hygiene::{ ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextKey, + raw_encode_syntax_context, }; use rustc_span::{ BlobDecoder, BytePos, ByteSymbol, CachingSourceMapView, ExpnData, ExpnHash, RelativeBytePos, @@ -223,8 +226,6 @@ impl OnDiskCache { (file_to_file_index, file_index_to_stable_id) }; - let hygiene_encode_context = HygieneEncodeContext::default(); - let mut encoder = CacheEncoder { tcx, encoder, @@ -233,7 +234,7 @@ impl OnDiskCache { interpret_allocs: Default::default(), caching_source_map_view: CachingSourceMapView::new(tcx.sess.source_map()), file_to_file_index, - hygiene_context: &hygiene_encode_context, + hygiene_context: Default::default(), symbol_index_table: Default::default(), query_values_index: Default::default(), side_effects_index: Default::default(), @@ -278,7 +279,8 @@ impl OnDiskCache { // Encode all hygiene data (`SyntaxContextData` and `ExpnData`) from the current // session. - hygiene_encode_context.encode( + HygieneEncodeContext::encode( + &Rc::clone(&encoder.hygiene_context), &mut encoder, |encoder, index, ctxt_data| { let pos = AbsoluteBytePos::new(encoder.position()); @@ -288,7 +290,7 @@ impl OnDiskCache { |encoder, expn_id, data, hash| { if expn_id.krate == LOCAL_CRATE { let pos = AbsoluteBytePos::new(encoder.position()); - encoder.encode_tagged(TAG_EXPN_DATA, data); + encoder.encode_tagged(TAG_EXPN_DATA, data.expect("local expn")); expn_data.insert(hash, pos); } else { foreign_expn_data.insert(hash, expn_id.local_id.as_u32()); @@ -774,7 +776,7 @@ impl_ref_decoder! {<'tcx> //- ENCODING ------------------------------------------------------------------- /// An encoder that can write to the incremental compilation cache. -pub struct CacheEncoder<'a, 'tcx> { +pub struct CacheEncoder<'tcx> { tcx: TyCtxt<'tcx>, encoder: FileEncoder<'static>, type_shorthands: FxHashMap, usize>, @@ -782,7 +784,7 @@ pub struct CacheEncoder<'a, 'tcx> { interpret_allocs: FxIndexSet, caching_source_map_view: CachingSourceMapView<'tcx>, file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>, - hygiene_context: &'a HygieneEncodeContext, + hygiene_context: Rc>, // Used for both `Symbol`s and `ByteSymbol`s. symbol_index_table: FxHashMap, @@ -790,14 +792,14 @@ pub struct CacheEncoder<'a, 'tcx> { side_effects_index: Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>, } -impl<'a, 'tcx> fmt::Debug for CacheEncoder<'a, 'tcx> { +impl<'tcx> fmt::Debug for CacheEncoder<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Add more details here if/when necessary. f.write_str("CacheEncoder") } } -impl<'a, 'tcx> CacheEncoder<'a, 'tcx> { +impl<'tcx> CacheEncoder<'tcx> { #[inline] fn source_file_index(&mut self, source_file: Arc) -> SourceFileIndex { self.file_to_file_index[&(&raw const *source_file)] @@ -866,13 +868,13 @@ impl<'a, 'tcx> CacheEncoder<'a, 'tcx> { } } -impl<'a, 'tcx> SpanEncoder for CacheEncoder<'a, 'tcx> { +impl<'tcx> SpanEncoder for CacheEncoder<'tcx> { fn encode_syntax_context(&mut self, syntax_context: SyntaxContext) { - rustc_span::hygiene::raw_encode_syntax_context(syntax_context, self.hygiene_context, self); + raw_encode_syntax_context(syntax_context, Rc::clone(&self.hygiene_context), self); } fn encode_expn_id(&mut self, expn_id: ExpnId) { - self.hygiene_context.schedule_expn_data_for_encoding(expn_id); + self.hygiene_context.borrow_mut().schedule_expn_data_for_encoding(expn_id); expn_id.expn_hash().encode(self); } @@ -944,7 +946,7 @@ impl<'a, 'tcx> SpanEncoder for CacheEncoder<'a, 'tcx> { } } -impl<'a, 'tcx> TyEncoder<'tcx> for CacheEncoder<'a, 'tcx> { +impl<'tcx> TyEncoder<'tcx> for CacheEncoder<'tcx> { const CLEAR_CROSS_CRATE: bool = false; #[inline] @@ -976,7 +978,7 @@ macro_rules! encoder_methods { } } -impl<'a, 'tcx> Encoder for CacheEncoder<'a, 'tcx> { +impl<'tcx> Encoder for CacheEncoder<'tcx> { encoder_methods! { emit_usize(usize); emit_u128(u128); @@ -999,8 +1001,8 @@ impl<'a, 'tcx> Encoder for CacheEncoder<'a, 'tcx> { // is used when a `CacheEncoder` having an `opaque::FileEncoder` is passed to `Encodable::encode`. // Unfortunately, we have to manually opt into specializations this way, given how `CacheEncoder` // and the encoding traits currently work. -impl<'a, 'tcx> Encodable> for [u8] { - fn encode(&self, e: &mut CacheEncoder<'a, 'tcx>) { +impl<'tcx> Encodable> for [u8] { + fn encode(&self, e: &mut CacheEncoder<'tcx>) { self.encode(&mut e.encoder); } } diff --git a/compiler/rustc_query_impl/src/incremental.rs b/compiler/rustc_query_impl/src/incremental.rs index 341c9f5e5068d..1a007ac55a4ea 100644 --- a/compiler/rustc_query_impl/src/incremental.rs +++ b/compiler/rustc_query_impl/src/incremental.rs @@ -19,19 +19,19 @@ fn all_inactive<'tcx, K>(state: &QueryState<'tcx, K>) -> bool { state.active.lock_shards().all(|shard| shard.is_empty()) } -pub(crate) fn encode_query_values<'tcx>(tcx: TyCtxt<'tcx>, encoder: &mut CacheEncoder<'_, 'tcx>) { +pub(crate) fn encode_query_values<'tcx>(tcx: TyCtxt<'tcx>, encoder: &mut CacheEncoder<'tcx>) { for_each_query_vtable!(CACHE_ON_DISK, tcx, |query| { encode_query_values_inner(tcx, query, encoder) }); } -fn encode_query_values_inner<'a, 'tcx, C, V>( +fn encode_query_values_inner<'tcx, C, V>( tcx: TyCtxt<'tcx>, query: &'tcx QueryVTable<'tcx, C>, - encoder: &mut CacheEncoder<'a, 'tcx>, + encoder: &mut CacheEncoder<'tcx>, ) where C: QueryCache>, - V: Erasable + Encodable>, + V: Erasable + Encodable>, { let _timer = tcx.prof.generic_activity_with_arg("encode_query_results_for", query.name); diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index fa0133a3c7fd8..3ca3fd0940f7f 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -24,7 +24,9 @@ // because getting it wrong can lead to nested `HygieneData::with` calls that // trigger runtime aborts. (Fortunately these are obvious and easy to fix.) +use std::cell::RefCell; use std::hash::Hash; +use std::rc::Rc; use std::sync::Arc; use std::{fmt, iter, mem}; @@ -1294,74 +1296,97 @@ impl DesugaringKind { #[derive(Default)] pub struct HygieneEncodeContext { /// All `SyntaxContexts` for which we have written `SyntaxContextData` into crate metadata. - /// This is `None` after we finish encoding `SyntaxContexts`, to ensure - /// that we don't accidentally try to encode any more `SyntaxContexts` - serialized_ctxts: Lock>, + serialized_ctxts: FxHashSet, /// The `SyntaxContexts` that we have serialized (e.g. as a result of encoding `Spans`) /// in the most recent 'round' of serializing. Serializing `SyntaxContextData` /// may cause us to serialize more `SyntaxContext`s, so serialize in a loop /// until we reach a fixed point. - latest_ctxts: Lock>, + latest_ctxts: FxHashSet, - serialized_expns: Lock>, - - latest_expns: Lock>, + serialized_expns: FxHashSet, + latest_expns: FxHashSet, } impl HygieneEncodeContext { /// Record the fact that we need to serialize the corresponding `ExpnData`. - pub fn schedule_expn_data_for_encoding(&self, expn: ExpnId) { - if !self.serialized_expns.lock().contains(&expn) { - self.latest_expns.lock().insert(expn); - } + #[inline] + pub fn schedule_expn_data_for_encoding(&mut self, expn: ExpnId) { + self.latest_expns.insert(expn); } pub fn encode( - &self, + h_ctxt: &RefCell, encoder: &mut T, mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextKey), - mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash), + mut encode_expn: impl FnMut(&mut T, ExpnId, Option<&ExpnData>, ExpnHash), ) { // When we serialize a `SyntaxContextData`, we may end up serializing // a `SyntaxContext` that we haven't seen before - while !self.latest_ctxts.lock().is_empty() || !self.latest_expns.lock().is_empty() { + + // Reuse the capacity between the loop iterations below. + let mut all_ctxt_data = vec![]; + let mut all_expn_data = vec![]; + + while { + let h_ctxt = h_ctxt.borrow(); + !h_ctxt.latest_ctxts.is_empty() || !h_ctxt.latest_expns.is_empty() + } { debug!( "encode_hygiene: Serializing a round of {:?} SyntaxContextData: {:?}", - self.latest_ctxts.lock().len(), - self.latest_ctxts + h_ctxt.borrow().latest_ctxts.len(), + h_ctxt.borrow().latest_ctxts ); + let mut mut_hctxt = h_ctxt.borrow_mut(); + // Consume the current round of syntax contexts. - // Drop the lock() temporary early. - // It's fine to iterate over a HashMap, because the serialization of the table + // It's fine to iterate over a HashSet, because the serialization of the table // that we insert data into doesn't depend on insertion order. #[allow(rustc::potential_query_instability)] - let latest_ctxts = { mem::take(&mut *self.latest_ctxts.lock()) }.into_iter(); - let all_ctxt_data: Vec<_> = HygieneData::with(|data| { - latest_ctxts - .map(|ctxt| (ctxt, data.syntax_context_data[ctxt.0 as usize].key())) - .collect() - }); - for (ctxt, ctxt_key) in all_ctxt_data { - if self.serialized_ctxts.lock().insert(ctxt) { - encode_ctxt(encoder, ctxt.0, &ctxt_key); + let latest_ctxts = { mem::take(&mut mut_hctxt.latest_ctxts) }.into_iter(); + + HygieneData::with(|data| { + for ctxt in latest_ctxts { + if !mut_hctxt.serialized_ctxts.insert(ctxt) { + continue; + } + + all_ctxt_data.push((ctxt.0, data.syntax_context_data[ctxt.0 as usize].key())); } + }); + + drop(mut_hctxt); + + for (idx, ctxt_key) in all_ctxt_data.drain(..) { + encode_ctxt(encoder, idx, &ctxt_key); } + let mut mut_hctxt = h_ctxt.borrow_mut(); + // Same as above, but for expansions instead of syntax contexts. #[allow(rustc::potential_query_instability)] - let latest_expns = { mem::take(&mut *self.latest_expns.lock()) }.into_iter(); - let all_expn_data: Vec<_> = HygieneData::with(|data| { - latest_expns - .map(|expn| (expn, data.expn_data(expn).clone(), data.expn_hash(expn))) - .collect() - }); - for (expn, expn_data, expn_hash) in all_expn_data { - if self.serialized_expns.lock().insert(expn) { - encode_expn(encoder, expn, &expn_data, expn_hash); + let latest_expns = { mem::take(&mut mut_hctxt.latest_expns) }.into_iter(); + HygieneData::with(|data| { + for expn in latest_expns { + if !mut_hctxt.serialized_expns.insert(expn) { + continue; + } + + // We need `data` only for local expansions, so don't `data` for non-local + // expansions. + // FIXME: completely remove this clone + let expn_data = expn.as_local().map(|id| data.local_expn_data(id).clone()); + all_expn_data.push((expn, expn_data, data.expn_hash(expn))); } + }); + + drop(mut_hctxt); + + for (expn, expn_data, expn_hash) in all_expn_data.drain(..) { + encode_expn(encoder, expn, expn_data.as_ref(), expn_hash); } } + debug!("encode_hygiene: Done serializing SyntaxContextData"); } } @@ -1484,14 +1509,13 @@ impl Decodable for LocalExpnId { } } +#[inline] pub fn raw_encode_syntax_context( ctxt: SyntaxContext, - context: &HygieneEncodeContext, + context: Rc>, e: &mut impl Encoder, ) { - if !context.serialized_ctxts.lock().contains(&ctxt) { - context.latest_ctxts.lock().insert(ctxt); - } + context.borrow_mut().latest_ctxts.insert(ctxt); ctxt.0.encode(e); } From 8e35cfe1f8d2efcaf70c82875ac9d5d0832f26f9 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 10 Sep 2026 14:12:09 +0800 Subject: [PATCH 26/29] Update platform support docs for `i686-pc-windows-msvc` As a Tier 1 (without host tools) target. - Fix an outdated claim that all T1 targets have host tools, since `i686-pc-windows-msvc` no longer does. - Remove a duplicate Tier 1 section. - Put `i686-pc-windows-msvc` under its own Tier 1 without host tools section. --- src/doc/rustc/src/platform-support.md | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index b6bf18a155051..816fc283887fc 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -25,7 +25,9 @@ are documented at our [Forge documentation site][forge]. Tier 1 targets can be thought of as "guaranteed to work". The Rust project builds official binary releases for each tier 1 target, and automated testing -ensures that each tier 1 target builds and passes tests after each change. +ensures that each tier 1 target builds and passes tests after each change. For +the full requirements, see [Tier 1 target +policy](target-tier-policy.md#tier-1-target-policy) in the Target Tier Policy. Tier 1 targets with host tools additionally support running tools like `rustc` and `cargo` natively on the target, and automated testing ensures that tests @@ -34,19 +36,17 @@ development platform, not just a compilation target. For the full requirements, see [Tier 1 with Host Tools](target-tier-policy.md#tier-1-with-host-tools) in the Target Tier Policy. -All tier 1 targets with host tools support the full standard library. +All tier 1 (with host tools) targets support the full standard library. target | notes -------|------- [`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+) [`aarch64-pc-windows-msvc`](platform-support/windows-msvc.md) | ARM64 Windows MSVC [`aarch64-unknown-linux-gnu`](platform-support/aarch64-unknown-linux-gnu.md) | ARM64 Linux (kernel 4.1+, glibc 2.17+) -[`i686-pc-windows-msvc`](platform-support/windows-msvc.md) | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment] `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI] [`x86_64-pc-windows-gnu`](platform-support/windows-gnu.md) | 64-bit MinGW (Windows 10+, Windows Server 2016+) [`x86_64-pc-windows-msvc`](platform-support/windows-msvc.md) | 64-bit MSVC (Windows 10+, Windows Server 2016+) `x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 3.2+, glibc 2.17+) - [^x86_32-floats-return-ABI]: Due to limitations of the C ABI, floating-point support on `i686` targets is non-compliant: floating-point return values are passed via an x87 register, so NaN payload bits can be lost. Functions with the default Rust ABI are not affected. See [issue #115567][x86-32-float-return-issue]. [^win32-msvc-alignment]: Due to non-standard behavior of MSVC, native C code on this target can cause types with an alignment of more than 4 bytes to be incorrectly aligned to only 4 bytes (this affects, e.g., `u64` and `i64`). Rust applies some mitigations to reduce the impact of this issue, but this can still cause unsoundness due to unsafe code that (correctly) assumes that references are always properly aligned. See [issue #112480](https://github.com/rust-lang/rust/issues/112480). @@ -54,16 +54,13 @@ target | notes [77071]: https://github.com/rust-lang/rust/issues/77071 [x86-32-float-return-issue]: https://github.com/rust-lang/rust/issues/115567 -## Tier 1 +## Tier 1 without Host Tools -Tier 1 targets can be thought of as "guaranteed to work". The Rust project -builds official binary releases for each tier 1 target, and automated testing -ensures that each tier 1 target builds and passes tests after each change. For -the full requirements, see [Tier 1 target -policy](target-tier-policy.md#tier-1-target-policy) in the Target Tier Policy. +target | notes +-------|------- +[`i686-pc-windows-msvc`](platform-support/windows-msvc.md) | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment] -At this time, all Tier 1 targets are [Tier 1 with Host -Tools](#tier-1-with-host-tools). +All tier 1 (without host tools) targets support the full standard library. ## Tier 2 with Host Tools From c5eb55cb8bae02933f1b5db0745262b68a846a41 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 10 Sep 2026 14:14:04 +0800 Subject: [PATCH 27/29] Fix target spec metadata for `i686-pc-windows-msvc` We no longer ship host tools for this target. --- compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs index 8f2746c461661..670cb5b5d10e6 100644 --- a/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/i686_pc_windows_msvc.rs @@ -25,7 +25,7 @@ pub(crate) fn target() -> Target { metadata: TargetMetadata { description: Some("32-bit MSVC (Windows 10+)".into()), tier: Some(1), - host_tools: Some(true), + host_tools: Some(false), std: Some(true), }, pointer_width: 32, From 7125897b479029f1ec59c8aec17f6680dfbc7e38 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Thu, 10 Sep 2026 14:16:56 +0800 Subject: [PATCH 28/29] Update platform support page for `windows-msvc` --- src/doc/rustc/src/platform-support/windows-msvc.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/windows-msvc.md b/src/doc/rustc/src/platform-support/windows-msvc.md index c4b56201e7968..d73577fdd1fe2 100644 --- a/src/doc/rustc/src/platform-support/windows-msvc.md +++ b/src/doc/rustc/src/platform-support/windows-msvc.md @@ -5,9 +5,11 @@ Windows MSVC targets. **Tier 1 with host tools:** - `aarch64-pc-windows-msvc`: Windows on ARM64. -- `i686-pc-windows-msvc`: Windows on 32-bit x86. - `x86_64-pc-windows-msvc`: Windows on 64-bit x86. +**Tier 1 without host tools:** +- `i686-pc-windows-msvc`: Windows on 32-bit x86. + ## Target maintainers [@ChrisDenton](https://github.com/ChrisDenton) @@ -28,6 +30,8 @@ Windows 10 or higher is required for client installs, Windows Server 2016 or hig The minimum supported Visual Studio version is 2017 but this support is not actively tested in CI. It is **highly** recommended to use the latest version of VS (currently VS 2022). +Only 64-bit `*-pc-windows-msvc` targets support host tools. + ### Platform details These targets fully implement the Rust standard library. From 04547c1dc476a90a671d864d6d9a945e3a7f4ab5 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Fri, 11 Sep 2026 16:27:10 +0800 Subject: [PATCH 29/29] Update VS 2022 => VS 2026 --- src/doc/rustc/src/platform-support/windows-msvc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/windows-msvc.md b/src/doc/rustc/src/platform-support/windows-msvc.md index d73577fdd1fe2..266a427ae9618 100644 --- a/src/doc/rustc/src/platform-support/windows-msvc.md +++ b/src/doc/rustc/src/platform-support/windows-msvc.md @@ -28,7 +28,7 @@ Windows 10 or higher is required for client installs, Windows Server 2016 or hig ### Host tooling The minimum supported Visual Studio version is 2017 but this support is not actively tested in CI. -It is **highly** recommended to use the latest version of VS (currently VS 2022). +It is **highly** recommended to use the latest version of VS (currently VS 2026). Only 64-bit `*-pc-windows-msvc` targets support host tools.