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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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 15d08109c4ab3414ad761aba86f61e59566d8092 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Wed, 9 Sep 2026 16:04:34 +0100 Subject: [PATCH 20/31] 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 ad8967754d755aac9aea1589c5ece5707a36bb84 Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 25 Mar 2026 22:51:43 +0800 Subject: [PATCH 21/31] 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 22/31] 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 23/31] 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 24/31] 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 25/31] 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 26/31] 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. From ff820f438f844847418cf0a56012f4f0d9db73ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 11 Aug 2026 14:10:08 +0200 Subject: [PATCH 27/31] rename resolver folders and their access functions --- .../src/diagnostics/region_errors.rs | 2 +- .../src/region_infer/opaque_types/mod.rs | 2 +- .../src/type_check/constraint_conversion.rs | 2 +- .../src/type_check/relate_tys.rs | 2 +- compiler/rustc_hir_analysis/src/autoderef.rs | 6 +- .../rustc_hir_analysis/src/check/check.rs | 8 +-- .../src/check/compare_impl_item.rs | 4 +- .../src/coherence/orphan.rs | 4 +- compiler/rustc_hir_analysis/src/collect.rs | 4 +- compiler/rustc_hir_typeck/src/callee.rs | 11 ++-- compiler/rustc_hir_typeck/src/cast.rs | 44 ++++++------- compiler/rustc_hir_typeck/src/closure.rs | 23 ++++--- compiler/rustc_hir_typeck/src/coercion.rs | 10 +-- compiler/rustc_hir_typeck/src/demand.rs | 8 +-- compiler/rustc_hir_typeck/src/expectation.rs | 12 ++-- compiler/rustc_hir_typeck/src/expr.rs | 32 +++++----- .../rustc_hir_typeck/src/expr_use_visitor.rs | 12 ++-- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 21 ++++--- .../src/fn_ctxt/adjust_fulfillment_errors.rs | 10 +-- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 22 ++++--- .../src/fn_ctxt/inspect_obligations.rs | 2 +- .../src/fn_ctxt/suggestions.rs | 8 +-- compiler/rustc_hir_typeck/src/inline_asm.rs | 6 +- compiler/rustc_hir_typeck/src/method/probe.rs | 19 ++++-- .../rustc_hir_typeck/src/method/suggest.rs | 10 +-- compiler/rustc_hir_typeck/src/op.rs | 6 +- compiler/rustc_hir_typeck/src/opaque_types.rs | 2 +- compiler/rustc_hir_typeck/src/pat.rs | 34 +++++----- compiler/rustc_hir_typeck/src/place_op.rs | 2 +- compiler/rustc_hir_typeck/src/upvar.rs | 6 +- compiler/rustc_hir_typeck/src/writeback.rs | 11 ++-- compiler/rustc_infer/src/infer/context.rs | 4 +- compiler/rustc_infer/src/infer/mod.rs | 18 +++--- .../rustc_infer/src/infer/opaque_types/mod.rs | 2 +- .../rustc_infer/src/infer/outlives/mod.rs | 2 +- .../src/infer/outlives/obligations.rs | 4 +- compiler/rustc_infer/src/infer/resolve.rs | 30 ++++----- .../rustc_infer/src/infer/snapshot/fudge.rs | 2 +- .../src/canonical/mod.rs | 4 +- .../rustc_next_trait_solver/src/normalize.rs | 10 +-- .../src/solve/assembly/mod.rs | 2 +- .../src/solve/eval_ctxt/mod.rs | 24 +++---- .../rustc_next_trait_solver/src/solve/mod.rs | 2 +- .../src/solve/trait_goals.rs | 8 ++- .../src/error_reporting/infer/mod.rs | 20 +++--- .../error_reporting/infer/need_type_info.rs | 14 ++--- .../nice_region_error/placeholder_error.rs | 18 +++--- .../error_reporting/infer/note_and_explain.rs | 2 +- .../src/error_reporting/infer/region.rs | 4 +- .../src/error_reporting/infer/suggest.rs | 6 +- .../src/error_reporting/traits/ambiguity.rs | 4 +- .../traits/fulfillment_errors.rs | 43 +++++++------ .../src/error_reporting/traits/mod.rs | 2 +- .../src/error_reporting/traits/overflow.rs | 10 +-- .../src/error_reporting/traits/suggestions.rs | 63 ++++++++++--------- compiler/rustc_trait_selection/src/infer.rs | 6 +- .../src/solve/delegate.rs | 13 ++-- .../src/solve/fulfill/derive_errors.rs | 6 +- .../src/solve/inspect/analyse.rs | 6 +- .../src/solve/normalize.rs | 4 +- .../src/traits/auto_trait.rs | 6 +- .../src/traits/coherence.rs | 9 +-- .../src/traits/effects.rs | 2 +- .../src/traits/fulfill.rs | 17 ++--- .../src/traits/implied_outlives_bounds.rs | 2 +- .../rustc_trait_selection/src/traits/mod.rs | 7 ++- .../src/traits/normalize.rs | 4 +- .../src/traits/outlives_bounds.rs | 6 +- .../src/traits/project.rs | 14 ++--- .../src/traits/query/type_op/custom.rs | 2 +- .../src/traits/select/candidate_assembly.rs | 10 +-- .../src/traits/select/mod.rs | 13 ++-- .../src/traits/specialize/mod.rs | 2 +- .../src/traits/structural_normalize.rs | 2 +- .../rustc_trait_selection/src/traits/wf.rs | 2 +- compiler/rustc_traits/src/codegen.rs | 2 +- .../rustc_traits/src/coroutine_witnesses.rs | 4 +- .../src/normalize_erasing_regions.rs | 2 +- compiler/rustc_type_ir/src/infer_ctxt.rs | 25 +++++--- compiler/rustc_type_ir/src/relate/combine.rs | 2 +- compiler/rustc_type_ir/src/universe.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/html/format.rs | 2 +- 83 files changed, 435 insertions(+), 382 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index a972b37cd42d2..8fd285f567535 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -954,7 +954,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { tcx, self.infcx.typing_env(self.infcx.param_env), fn_did, - self.infcx.resolve_vars_if_possible(args.no_bound_vars().unwrap()), + self.infcx.deeply_resolve_ignoring_regions(args.no_bound_vars().unwrap()), ) else { return; }; diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs index a154078b7ad86..ad15c5750b092 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs @@ -73,7 +73,7 @@ pub(crate) fn clone_and_resolve_opaque_types<'tcx>( let opaque_types = opaque_types .into_iter() .map(|entry| { - fold_regions(infcx.tcx, infcx.resolve_vars_if_possible(entry), |r, _| { + fold_regions(infcx.tcx, infcx.deeply_resolve_ignoring_regions(entry), |r, _| { let vid = if let ty::RePlaceholder(placeholder) = r.kind() { constraints.placeholder_region(infcx, placeholder).as_var() } else { diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 113908fba6702..c36cda49ab768 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -161,7 +161,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { GenericArgKind::Type(mut t1) => { // Scraped constraints may have had inference vars. - t1 = self.infcx.resolve_vars_if_possible(t1); + t1 = self.infcx.deeply_resolve_ignoring_regions(t1); let implicit_region_bound = ty::Region::new_var(tcx, universal_regions.implicit_region_bound()); diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index c922d1a9f0f86..10974a5157b10 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -145,7 +145,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> { ty, )?; let new_var = - infcx.resolve_vars_if_possible(Ty::new_infer(infcx.tcx, ty::TyVar(ty_vid))); + infcx.deeply_resolve_ignoring_regions(Ty::new_infer(infcx.tcx, ty::TyVar(ty_vid))); // Any regions in this new type must be live everywhere, so we mark them as such. // (It may be that it only needs to be live where the opaque type itself is - which diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 01d0c8483ac54..883bfa2b46b9b 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { // and Deref, and this has benefits for const and the emitted MIR. let (kind, new_ty) = if let Some(ty) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) { - debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty)); + debug_assert_eq!(ty, self.infcx.deeply_resolve_ignoring_regions(ty)); (AutoderefKind::Builtin, ty) } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { // The overloaded deref check already normalizes the pointee type. @@ -123,7 +123,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { param_env, state: AutoderefSnapshot { steps: vec![], - cur_ty: infcx.resolve_vars_if_possible(base_ty), + cur_ty: infcx.deeply_resolve_ignoring_regions(base_ty), obligations: PredicateObligations::new(), at_start: true, reached_recursion_limit: false, @@ -171,7 +171,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); self.state.obligations.extend(obligations); - Some(self.infcx.resolve_vars_if_possible(normalized_ty)) + Some(self.infcx.deeply_resolve_ignoring_regions(normalized_ty)) } #[instrument(level = "debug", skip(self), ret)] diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index d5bc834b831c7..b9f93111e8290 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -427,8 +427,8 @@ fn check_opaque_meets_bounds<'tcx>( } else { // Check that any hidden types found during wf checking match the hidden types that `type_of` sees. for (mut key, mut ty) in infcx.take_opaque_types() { - ty.ty = infcx.resolve_vars_if_possible(ty.ty); - key = infcx.resolve_vars_if_possible(key); + ty.ty = infcx.deeply_resolve_ignoring_regions(ty.ty); + key = infcx.deeply_resolve_ignoring_regions(key); sanity_check_found_hidden_type(tcx, key, ty)?; } Ok(()) @@ -2314,8 +2314,8 @@ pub(super) fn check_coroutine_obligations( // Check that any hidden types found when checking these stalled coroutine obligations // are valid. for (key, ty) in infcx.take_opaque_types() { - let hidden_type = infcx.resolve_vars_if_possible(ty); - let key = infcx.resolve_vars_if_possible(key); + let hidden_type = infcx.deeply_resolve_ignoring_regions(ty); + let key = infcx.deeply_resolve_ignoring_regions(key); sanity_check_found_hidden_type(tcx, key, hidden_type)?; } } else { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index d49c3b2869bd3..e0b9f7dd58bc9 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -584,9 +584,9 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( .iter() .map(|(_, &(ty, _))| { assert!( - infcx.resolve_vars_if_possible(ty) == ty && ty.is_ty_var(), + infcx.deeply_resolve_ignoring_regions(ty) == ty && ty.is_ty_var(), "{ty:?} should not have been constrained via normalization", - ty = infcx.resolve_vars_if_possible(ty) + ty = infcx.deeply_resolve_ignoring_regions(ty) ); idx += 1; ( diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index c970799d318fe..f67ed5e44d20e 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -333,7 +333,7 @@ fn orphan_check<'tcx>( let ocx = traits::ObligationCtxt::new(&infcx); let ty = ocx.normalize(&cause, ty::ParamEnv::empty(), Unnormalized::new_wip(user_ty)); - let ty = infcx.resolve_vars_if_possible(ty); + let ty = infcx.deeply_resolve_ignoring_regions(ty); let errors = ocx.try_evaluate_obligations(); if !errors.no_errors() { return Ok(user_ty); @@ -377,7 +377,7 @@ fn orphan_check<'tcx>( id_arg, ); } - infcx.resolve_vars_if_possible(tys) + infcx.deeply_resolve_ignoring_regions(tys) }); OrphanCheckErr::NonLocalInputType(tys) } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 2e4da8d948f07..e123906041c5f 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1539,11 +1539,11 @@ pub fn suggest_impl_trait<'tcx>( ); // FIXME(compiler-errors): We may benefit from resolving regions here. if ocx.try_evaluate_obligations().no_errors() - && let item_ty = infcx.resolve_vars_if_possible(item_ty) + && let item_ty = infcx.deeply_resolve_ignoring_regions(item_ty) && let Some(item_ty) = item_ty.make_suggestable(infcx.tcx, false, None) && let Some(sugg) = formatter( infcx.tcx, - infcx.resolve_vars_if_possible(args), + infcx.deeply_resolve_ignoring_regions(args), trait_def_id, assoc_item_def_id, item_ty, diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index e250ec4c7af40..47ba64a591aeb 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -103,7 +103,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => self.check_expr(callee_expr), }; - let expr_ty = self.resolve_vars_with_obligations(original_callee_ty); + let expr_ty = self.deeply_resolve_ignoring_regions_with_obligations(original_callee_ty); let mut autoderef = self.autoderef(callee_expr.span, expr_ty); let mut result = None; @@ -237,7 +237,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg_exprs: &'tcx [hir::Expr<'tcx>], autoderef: &Autoderef<'a, 'tcx>, ) -> Option> { - let adjusted_ty = self.resolve_vars_with_obligations(autoderef.final_ty()); + let adjusted_ty = + self.deeply_resolve_ignoring_regions_with_obligations(autoderef.final_ty()); // If the callee is a function pointer or a closure, then we're all set. match *adjusted_ty.kind() { @@ -736,7 +737,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return do_check(); } - resolved_inputs = self.resolve_vars_if_possible(formal_input_tys.to_vec()); + resolved_inputs = self.deeply_resolve_ignoring_regions(formal_input_tys.to_vec()); } // Fool typechecker by placing an adjusted type of the first arg to avoid errors. @@ -873,7 +874,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (rest_span, format!(").{}({rest_snippet}", segment.ident)), ] }; - let self_ty = self.resolve_vars_if_possible(pick.callee.sig.inputs()[0]); + let self_ty = self.deeply_resolve_ignoring_regions(pick.callee.sig.inputs()[0]); diag.multipart_suggestion( format!( "use the `.` operator to call the method `{}{}` on `{self_ty}`", @@ -925,7 +926,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some((removal_span, descr, rustc_hir_pretty::qpath_to_string(self, qpath))); } - let callee_ty = self.resolve_vars_if_possible(callee_ty); + let callee_ty = self.deeply_resolve_ignoring_regions(callee_ty); let mut path = None; let mut err = self.dcx().create_err(diagnostics::InvalidCallee { span: callee_expr.span, diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index a3ed9d0e16e86..d5677ff087ac8 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -96,14 +96,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Result>, ErrorGuaranteed> { debug!("pointer_kind({:?}, {:?})", t, span); - let t = self.resolve_vars_if_possible(t); + let t = self.deeply_resolve_ignoring_regions(t); t.error_reported()?; if self.type_is_sized_modulo_regions(self.param_env, t) { return Ok(Some(PointerKind::Thin)); } - let t = self.resolve_vars_with_obligations(t); + let t = self.deeply_resolve_ignoring_regions_with_obligations(t); Ok(match *t.kind() { ty::Slice(_) | ty::Str => Some(PointerKind::Length), @@ -396,7 +396,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { err.emit(); } CastError::CastToBool => { - let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); + let expr_ty = fcx.deeply_resolve_ignoring_regions(self.expr_ty); let help = if self.expr_ty.is_numeric() { diagnostics::CannotCastToBoolHelp::Numeric( self.expr_span.shrink_to_hi().with_hi(self.span.hi()), @@ -539,8 +539,8 @@ impl<'a, 'tcx> CastCheck<'tcx> { ) { // Check `impl From for self.cast_ty {}` for accurate suggestion: if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From) { - let ty = fcx.resolve_vars_if_possible(self.cast_ty); - let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); + let ty = fcx.deeply_resolve_ignoring_regions(self.cast_ty); + let expr_ty = fcx.deeply_resolve_ignoring_regions(self.expr_ty); if fcx .infcx .type_implements_trait(from_trait, [ty, expr_ty], fcx.param_env) @@ -604,8 +604,8 @@ impl<'a, 'tcx> CastCheck<'tcx> { err.emit(); } CastError::SizedUnsizedCast => { - let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); - let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); + let cast_ty = fcx.deeply_resolve_ignoring_regions(self.cast_ty); + let expr_ty = fcx.deeply_resolve_ignoring_regions(self.expr_ty); fcx.dcx().emit_err(diagnostics::CastThinPointerToWidePointer { span: self.span, expr_ty, @@ -615,8 +615,8 @@ impl<'a, 'tcx> CastCheck<'tcx> { } CastError::IntToWideCast(known_metadata) => { let expr_if_nightly = fcx.tcx.sess.is_nightly_build().then_some(self.expr_span); - let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); - let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); + let cast_ty = fcx.deeply_resolve_ignoring_regions(self.cast_ty); + let expr_ty = fcx.deeply_resolve_ignoring_regions(self.expr_ty); let metadata = known_metadata.unwrap_or("type-specific metadata"); let known_wide = known_metadata.is_some(); let span = self.cast_span; @@ -659,8 +659,8 @@ impl<'a, 'tcx> CastCheck<'tcx> { }); } CastError::CastEnumDrop => { - let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); - let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); + let expr_ty = fcx.deeply_resolve_ignoring_regions(self.expr_ty); + let cast_ty = fcx.deeply_resolve_ignoring_regions(self.cast_ty); fcx.dcx().emit_err(diagnostics::CastEnumDrop { span: self.span, expr_ty, cast_ty }); } @@ -707,7 +707,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { self.expr_ty, E0620, "cast to unsized type: `{}` as `{}`", - fcx.resolve_vars_if_possible(self.expr_ty), + fcx.deeply_resolve_ignoring_regions(self.expr_ty), tstr ); match self.expr_ty.kind() { @@ -747,8 +747,8 @@ impl<'a, 'tcx> CastCheck<'tcx> { } else { (false, TRIVIAL_CASTS) }; - let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); - let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); + let expr_ty = fcx.deeply_resolve_ignoring_regions(self.expr_ty); + let cast_ty = fcx.deeply_resolve_ignoring_regions(self.cast_ty); fcx.tcx.emit_node_span_lint( lint, self.expr.hir_id, @@ -788,8 +788,8 @@ impl<'a, 'tcx> CastCheck<'tcx> { fn expr_span_for_type_resolution(&self, fcx: &FnCtxt<'a, 'tcx>) -> Span { if let hir::ExprKind::Index(_, idx, _) = self.expr.kind - && fcx.resolve_vars_if_possible(self.expr_ty).is_ty_var() - && fcx.resolve_vars_if_possible(fcx.node_ty(idx.hir_id)).is_ty_var() + && fcx.deeply_resolve_ignoring_regions(self.expr_ty).is_ty_var() + && fcx.deeply_resolve_ignoring_regions(fcx.node_ty(idx.hir_id)).is_ty_var() { index_operand_ambiguity_span(idx) } else { @@ -801,7 +801,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { pub(crate) fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) { let expr_span = self.expr_span_for_type_resolution(fcx); self.expr_ty = fcx.structurally_resolve_type(expr_span, self.expr_ty); - self.cast_ty = fcx.resolve_vars_with_obligations(self.cast_ty); + self.cast_ty = fcx.deeply_resolve_ignoring_regions_with_obligations(self.cast_ty); if self.cast_ty.is_ty_var() { self.cast_ty = if let Some(guar) = self.try_report_ambiguous_binop_for_infer_cast(fcx) { let err = Ty::new_error(fcx.tcx, guar); @@ -863,7 +863,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { .pending_obligations() .into_iter() .filter_map(|mut obligation| { - let predicate = fcx.resolve_vars_if_possible(obligation.predicate); + let predicate = fcx.deeply_resolve_ignoring_regions(obligation.predicate); if !matches!( predicate.kind().skip_binder(), ty::PredicateKind::Clause(ty::ClauseKind::Trait(_)) @@ -877,8 +877,8 @@ impl<'a, 'tcx> CastCheck<'tcx> { else { return None; }; - let lhs_ty = fcx.resolve_vars_if_possible(fcx.node_ty(*lhs_hir_id)); - let rhs_ty = fcx.resolve_vars_if_possible(fcx.node_ty(*rhs_hir_id)); + let lhs_ty = fcx.deeply_resolve_ignoring_regions(fcx.node_ty(*lhs_hir_id)); + let rhs_ty = fcx.deeply_resolve_ignoring_regions(fcx.node_ty(*rhs_hir_id)); if (fcx.tcx.hir_span(*lhs_hir_id).contains(cast_span) && lhs_ty.contains(self.cast_ty)) @@ -1203,8 +1203,8 @@ impl<'a, 'tcx> CastCheck<'tcx> { mut m_cast: ty::TypeAndMut<'tcx>, ) -> Result> { // array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const - m_expr.ty = fcx.resolve_vars_with_obligations(m_expr.ty); - m_cast.ty = fcx.resolve_vars_with_obligations(m_cast.ty); + m_expr.ty = fcx.deeply_resolve_ignoring_regions_with_obligations(m_expr.ty); + m_cast.ty = fcx.deeply_resolve_ignoring_regions_with_obligations(m_cast.ty); if m_expr.mutbl >= m_cast.mutbl && let ty::Array(ety, _) = m_expr.ty.kind() diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index de2f152011dbe..f6a97f04d99e4 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -60,9 +60,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // closure sooner rather than later, so first examine the expected // type, and see if can glean a closure kind from there. let (expected_sig, expected_kind) = match expected.to_option(self) { - Some(ty) => { - self.deduce_closure_signature(self.resolve_vars_with_obligations(ty), closure.kind) - } + Some(ty) => self.deduce_closure_signature( + self.deeply_resolve_ignoring_regions_with_obligations(ty), + closure.kind, + ), None => (None, None), }; @@ -411,7 +412,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let inferred_fnptr_sig = Ty::new_fn_ptr(self.tcx, inferred_sig.sig); self.demand_eqtype(span, inferred_fnptr_sig, generalized_fnptr_sig); - let resolved_sig = self.resolve_vars_if_possible(generalized_fnptr_sig); + let resolved_sig = self.deeply_resolve_ignoring_regions(generalized_fnptr_sig); if resolved_sig.visit_with(&mut MentionsTy { expected_ty }).is_continue() { expected_sig = Some(ExpectedSig { @@ -517,7 +518,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { cause_span: Option, projection: ty::PolyProjectionClause<'tcx>, ) -> Option> { - let projection = self.resolve_vars_if_possible(projection); + let projection = self.deeply_resolve_ignoring_regions(projection); let arg_param_ty = projection.skip_binder().projection_term.args.type_at(1); debug!(?arg_param_ty); @@ -562,7 +563,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { cause_span: Option, projection: ty::PolyProjectionClause<'tcx>, ) -> Option> { - let projection = self.resolve_vars_if_possible(projection); + let projection = self.deeply_resolve_ignoring_regions(projection); let arg_param_ty = projection.skip_binder().projection_term.args.type_at(1); debug!(?arg_param_ty); @@ -851,8 +852,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )?; all_obligations.extend(obligations); - let inputs = - supplied_sig.inputs().into_iter().map(|&ty| self.resolve_vars_if_possible(ty)); + let inputs = supplied_sig + .inputs() + .into_iter() + .map(|&ty| self.deeply_resolve_ignoring_regions(ty)); let fn_sig_kind = FnSigKind::default() .set_abi(ExternAbi::RustCall) @@ -959,7 +962,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let closure_span = self.tcx.def_span(body_def_id); let ret_ty = ret_coercion.borrow().expected_ty(); - let ret_ty = self.resolve_vars_with_obligations(ret_ty); + let ret_ty = self.deeply_resolve_ignoring_regions_with_obligations(ret_ty); let get_future_output = |clause: ty::Clause<'tcx>, span| { // Search for a pending obligation like @@ -1064,7 +1067,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Extract the type from the projection. Note that there can // be no bound variables in this type because the "self type" // does not have any regions in it. - let output_ty = self.resolve_vars_if_possible(predicate.term); + let output_ty = self.deeply_resolve_ignoring_regions(predicate.term); debug!("deduce_future_output_from_projection: output_ty={:?}", output_ty); // This is a projection on a Fn trait so will always be a type. Some(output_ty.expect_type()) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index a54fe8032bc45..b858c6d4a86f3 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -736,7 +736,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))) if traits.contains(&trait_pred.def_id()) => { - self.resolve_vars_if_possible(trait_pred) + self.deeply_resolve_ignoring_regions(trait_pred) } _ => { coercion.obligations.push(obligation); @@ -1140,7 +1140,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { allow_two_phase: AllowTwoPhase, cause: Option>, ) -> RelateResult<'tcx, Ty<'tcx>> { - let source = self.resolve_vars_with_obligations(expr_ty); + let source = self.deeply_resolve_ignoring_regions_with_obligations(expr_ty); debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); let cause = @@ -1335,8 +1335,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { new: &hir::Expr<'_>, new_ty: Ty<'tcx>, ) -> RelateResult<'tcx, Ty<'tcx>> { - let prev_ty = self.resolve_vars_with_obligations(prev_ty); - let new_ty = self.resolve_vars_with_obligations(new_ty); + let prev_ty = self.deeply_resolve_ignoring_regions_with_obligations(prev_ty); + let new_ty = self.deeply_resolve_ignoring_regions_with_obligations(new_ty); debug!( "coercion::try_find_coercion_lub({:?}, {:?}, exprs={:?} exprs)", prev_ty, @@ -1755,7 +1755,7 @@ impl<'tcx> CoerceMany<'tcx> { fcx.set_tainted_by_errors( fcx.dcx().span_delayed_bug(cause.span, "coercion error but no error emitted"), ); - let (expected, found) = fcx.resolve_vars_if_possible((expected, found)); + let (expected, found) = fcx.deeply_resolve_ignoring_regions((expected, found)); let mut err; let mut unsized_return = false; diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 659bb844702aa..830d8905ec8d8 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -261,7 +261,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, allow_two_phase: AllowTwoPhase, ) -> Result, Diag<'a>> { - let expected = self.resolve_vars_with_obligations(expected); + let expected = self.deeply_resolve_ignoring_regions_with_obligations(expected); let e = match self.coerce(expr, checked_ty, expected, allow_two_phase, None) { Ok(ty) => return Ok(ty), @@ -276,7 +276,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); let expr = expr.peel_drop_temps(); let cause = self.misc(expr.span); - let expr_ty = self.resolve_vars_if_possible(checked_ty); + let expr_ty = self.deeply_resolve_ignoring_regions(checked_ty); let mut err = self.err_ctxt().report_mismatched_types(&cause, self.param_env, expected, expr_ty, e); @@ -423,7 +423,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Yeet the errors, we're already reporting errors. errs.clear(); }); - Some(self.resolve_vars_if_possible(possible_rcvr_ty)) + Some(self.deeply_resolve_ignoring_regions(possible_rcvr_ty)) }); let Some(rcvr_ty) = possible_rcvr_ty else { return false }; rcvr_ty @@ -546,7 +546,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .borrow() .type_dependent_def_id(parent_expr.hir_id) && let ideal_arg_ty = - self.resolve_vars_if_possible(ideal_method.sig.inputs()[idx + 1]) + self.deeply_resolve_ignoring_regions(ideal_method.sig.inputs()[idx + 1]) && !ideal_arg_ty.has_non_region_infer() { self.emit_type_mismatch_suggestions( diff --git a/compiler/rustc_hir_typeck/src/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs index 37c8d7b2ae24e..f3950f2574268 100644 --- a/compiler/rustc_hir_typeck/src/expectation.rs +++ b/compiler/rustc_hir_typeck/src/expectation.rs @@ -46,7 +46,7 @@ impl<'a, 'tcx> Expectation<'tcx> { ) -> Expectation<'tcx> { match *self { ExpectHasType(ety) => { - let ety = fcx.resolve_vars_with_obligations(ety); + let ety = fcx.deeply_resolve_ignoring_regions_with_obligations(ety); if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation } } ExpectRvalueLikeUnsized(ety) => ExpectRvalueLikeUnsized(ety), @@ -93,9 +93,11 @@ impl<'a, 'tcx> Expectation<'tcx> { fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { match self { NoExpectation => NoExpectation, - ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(t)), - ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(t)), - ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(t)), + ExpectCastableToType(t) => ExpectCastableToType(fcx.deeply_resolve_ignoring_regions(t)), + ExpectHasType(t) => ExpectHasType(fcx.deeply_resolve_ignoring_regions(t)), + ExpectRvalueLikeUnsized(t) => { + ExpectRvalueLikeUnsized(fcx.deeply_resolve_ignoring_regions(t)) + } } } @@ -112,7 +114,7 @@ impl<'a, 'tcx> Expectation<'tcx> { /// such a constraint, if it exists. pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { match self { - ExpectHasType(ty) => Some(fcx.resolve_vars_if_possible(ty)), + ExpectHasType(ty) => Some(fcx.deeply_resolve_ignoring_regions(ty)), NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None, } } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index cc2be9d392b36..06dbd06eb191b 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -82,7 +82,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // While we don't allow *arbitrary* coercions here, we *do* allow // coercions from ! to `expected`. - if self.resolve_vars_with_obligations(ty).is_never() + if self.deeply_resolve_ignoring_regions_with_obligations(ty).is_never() && self.tcx.expr_guaranteed_to_constitute_read_for_never(expr) { if let Some(adjustments) = self.typeck_results.borrow().adjustments().get(expr.hir_id) { @@ -271,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) => self.check_expr_path(qpath, expr, call_expr_and_args), _ => self.check_expr_kind(expr, expected), }; - let ty = self.resolve_vars_if_possible(ty); + let ty = self.deeply_resolve_ignoring_regions(ty); // Warn for non-block expressions with diverging children. match expr.kind { @@ -300,7 +300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // unless it's a place expression that isn't being read from, in which case // diverging would be unsound since we may never actually read the `!`. // e.g. `let _ = *never_ptr;` with `never_ptr: *const !`. - if self.resolve_vars_with_obligations(ty).is_never() + if self.deeply_resolve_ignoring_regions_with_obligations(ty).is_never() && self.tcx.expr_guaranteed_to_constitute_read_for_never(expr) { self.diverges.set(self.diverges.get() | Diverges::always(expr.span)); @@ -464,7 +464,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| { - match self.resolve_vars_with_obligations(ty).kind() { + match self.deeply_resolve_ignoring_regions_with_obligations(ty).kind() { ty::Ref(_, ty, _) | ty::RawPtr(ty, _) => { if oprnd.is_syntactic_place_expr() { // Places may legitimately have unsized types. @@ -1480,7 +1480,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Expectation<'tcx>, ) -> Ty<'tcx> { let rcvr_t = self.check_expr(rcvr); - let rcvr_t = self.resolve_vars_with_obligations(rcvr_t); + let rcvr_t = self.deeply_resolve_ignoring_regions_with_obligations(rcvr_t); match self.lookup_method(rcvr_t, segment, segment.ident.span, expr, rcvr, args) { Ok(method) => { @@ -1551,9 +1551,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Find the type of `e`. Supply hints based on the type we are casting to, // if appropriate. let t_cast = self.lower_ty_saving_user_provided_ty(t); - let t_cast = self.resolve_vars_if_possible(t_cast); + let t_cast = self.deeply_resolve_ignoring_regions(t_cast); let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast)); - let t_expr = self.resolve_vars_if_possible(t_expr); + let t_expr = self.deeply_resolve_ignoring_regions(t_expr); // Eagerly check for some obvious errors. if let Err(guar) = (t_expr, t_cast).error_reported() { @@ -1675,11 +1675,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let coerce_to = expected .to_option(self) .and_then(|uty| { - self.resolve_vars_with_obligations(uty) + self.deeply_resolve_ignoring_regions_with_obligations(uty) .builtin_index() // Avoid using the original type variable as the coerce_to type, as it may resolve // during the first coercion instead of being the LUB type. - .filter(|t| !self.resolve_vars_with_obligations(*t).is_ty_var()) + .filter(|t| { + !self.deeply_resolve_ignoring_regions_with_obligations(*t).is_ty_var() + }) }) .unwrap_or_else(|| self.next_ty_var(expr.span)); let mut coerce = CoerceMany::with_capacity(coerce_to, args.len()); @@ -1804,7 +1806,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let mut expectations = expected .only_has_type(self) - .and_then(|ty| self.resolve_vars_with_obligations(ty).opt_tuple_fields()) + .and_then(|ty| { + self.deeply_resolve_ignoring_regions_with_obligations(ty).opt_tuple_fields() + }) .unwrap_or_default() .iter(); @@ -1878,7 +1882,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let tcx = self.tcx; - let adt_ty = self.resolve_vars_with_obligations(adt_ty); + let adt_ty = self.deeply_resolve_ignoring_regions_with_obligations(adt_ty); let adt_ty_hint = expected.only_has_type(self).and_then(|expected| { self.fudge_inference_if_ok(|| { let ocx = ObligationCtxt::new(self); @@ -1886,7 +1890,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !ocx.try_evaluate_obligations().no_errors() { return Err(TypeError::Mismatch); } - Ok(self.resolve_vars_if_possible(adt_ty)) + Ok(self.deeply_resolve_ignoring_regions(adt_ty)) }) .ok() }); @@ -2144,7 +2148,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - self.resolve_vars_if_possible(fru_ty) + self.deeply_resolve_ignoring_regions(fru_ty) }) .collect(); // The use of fresh args that we have subtyped against @@ -2168,7 +2172,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let fresh_base_ty = Ty::new_adt(self.tcx, *adt, fresh_args); self.check_expr_has_type_or_error( base_expr, - self.resolve_vars_if_possible(fresh_base_ty), + self.deeply_resolve_ignoring_regions(fresh_base_ty), |_| {}, ); fru_tys diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index e8f912165a4c5..47079ccbb1804 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -157,7 +157,7 @@ pub trait TypeInformationCtxt<'tcx> { fn typeck_results(&self) -> Self::TypeckResults<'_>; - fn resolve_vars_if_possible>>(&self, t: T) -> T; + fn deeply_resolve_ignoring_regions>>(&self, t: T) -> T; fn structurally_resolve_type(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>; @@ -188,8 +188,8 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> { self.typeck_results.borrow() } - fn resolve_vars_if_possible>>(&self, t: T) -> T { - self.infcx.resolve_vars_if_possible(t) + fn deeply_resolve_ignoring_regions>>(&self, t: T) -> T { + self.infcx.deeply_resolve_ignoring_regions(t) } fn structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { @@ -242,7 +242,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) { ty } - fn resolve_vars_if_possible>>(&self, t: T) -> T { + fn deeply_resolve_ignoring_regions>>(&self, t: T) -> T { t } @@ -1127,7 +1127,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx ) -> Result, Cx::Error> { match ty { Some(ty) => { - let ty = self.cx.resolve_vars_if_possible(ty); + let ty = self.cx.deeply_resolve_ignoring_regions(ty); self.cx.error_reported_in_ty(ty)?; Ok(ty) } @@ -1266,7 +1266,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx where F: FnOnce() -> Result, Cx::Error>, { - let target = self.cx.resolve_vars_if_possible(adjustment.target); + let target = self.cx.deeply_resolve_ignoring_regions(adjustment.target); match adjustment.kind { adjustment::Adjust::Deref(deref_kind) => { // Equivalent to *expr or something similar. diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index b59dc21981ce6..e09084cf51c23 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -108,11 +108,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Resolves type and const variables in `t` if possible. Unlike the infcx - /// version (resolve_vars_if_possible), this version will + /// version (deeply_resolve_ignoring_regions), this version will /// also select obligations if it seems useful, in an effort /// to get more type information. #[instrument(skip(self), level = "debug", ret)] - pub(crate) fn resolve_vars_with_obligations>>( + pub(crate) fn deeply_resolve_ignoring_regions_with_obligations< + T: TypeFoldable>, + >( &self, mut t: T, ) -> T { @@ -123,7 +125,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // If `t` is a type variable, see whether we already know what it is. - t = self.resolve_vars_if_possible(t); + t = self.deeply_resolve_ignoring_regions(t); if !t.has_non_region_infer() { debug!(?t); return t; @@ -134,7 +136,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // indirect dependencies that don't seem worth tracking // precisely. self.select_obligations_where_possible(|_| {}); - self.resolve_vars_if_possible(t) + self.deeply_resolve_ignoring_regions(t) } pub(crate) fn record_deferred_call_resolution( @@ -166,7 +168,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[inline] pub(crate) fn write_ty(&self, id: HirId, ty: Ty<'tcx>) { - debug!("write_ty({:?}, {:?}) in fcx {}", id, self.resolve_vars_if_possible(ty), self.tag()); + debug!( + "write_ty({:?}, {:?}) in fcx {}", + id, + self.deeply_resolve_ignoring_regions(ty), + self.tag() + ); let mut typeck = self.typeck_results.borrow_mut(); let mut node_ty = typeck.node_types_mut(); @@ -1473,7 +1480,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp: Span, ct: ty::Const<'tcx>, ) -> ty::Const<'tcx> { - let ct = self.resolve_vars_with_obligations(ct); + let ct = self.deeply_resolve_ignoring_regions_with_obligations(ct); if self.next_trait_solver() && let ty::ConstKind::Alias(..) = ct.kind() @@ -1508,7 +1515,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// If no resolution is possible, then an error is reported. /// Numeric inference variables may be left unresolved. pub(crate) fn structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - let ty = self.resolve_vars_with_obligations(ty); + let ty = self.deeply_resolve_ignoring_regions_with_obligations(ty); if !ty.is_ty_var() { ty } else { self.type_must_be_known_at_this_point(sp, ty) } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index be24a5e7d0b8c..ea0aa9db46a9c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -196,18 +196,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let hir::ExprKind::Index(indexed_expr, idx, _) = rhs_expr.kind else { return false; }; - if !self.resolve_vars_if_possible(self.node_ty(idx.hir_id)).is_ty_var() { + if !self.deeply_resolve_ignoring_regions(self.node_ty(idx.hir_id)).is_ty_var() { return false; } - let lhs_ty = self.resolve_vars_if_possible(self.node_ty(lhs_expr.hir_id)); - let indexed_ty = self.resolve_vars_if_possible(self.node_ty(indexed_expr.hir_id)); + let lhs_ty = self.deeply_resolve_ignoring_regions(self.node_ty(lhs_expr.hir_id)); + let indexed_ty = self.deeply_resolve_ignoring_regions(self.node_ty(indexed_expr.hir_id)); let rhs_ty = match *indexed_ty.kind() { ty::Array(element_ty, _) | ty::Slice(element_ty) => element_ty, ty::Ref(_, pointee_ty, _) => match *pointee_ty.kind() { ty::Array(element_ty, _) | ty::Slice(element_ty) => element_ty, - _ => self.resolve_vars_if_possible(self.node_ty(rhs_expr.hir_id)), + _ => self.deeply_resolve_ignoring_regions(self.node_ty(rhs_expr.hir_id)), }, - _ => self.resolve_vars_if_possible(self.node_ty(rhs_expr.hir_id)), + _ => self.deeply_resolve_ignoring_regions(self.node_ty(rhs_expr.hir_id)), }; if !self.binop_accepts_types(binop.node, lhs_ty, rhs_ty) { return false; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index ba44d1966d971..9859a1ad27444 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -246,7 +246,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut expected_input_tys: Option> = expectation .only_has_type(self) .and_then(|expected_output| { - let formal_output = self.resolve_vars_with_obligations(formal_output); + let formal_output = + self.deeply_resolve_ignoring_regions_with_obligations(formal_output); // FIXME(#149379): This operation results in expected input // types which are potentially not well-formed or for whom the // function where-bounds don't actually hold. This results @@ -283,7 +284,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(Some( formal_input_tys .iter() - .map(|&ty| self.resolve_vars_if_possible(ty)) + .map(|&ty| self.deeply_resolve_ignoring_regions(ty)) .collect::>(), )) }) @@ -387,7 +388,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Cause selection errors caused by resolving a single argument to point at the // argument and not the call. This lets us customize the span pointed to in the // fulfillment error to be more accurate. - let coerced_ty = self.resolve_vars_with_obligations(coerced_ty); + let coerced_ty = self.deeply_resolve_ignoring_regions_with_obligations(coerced_ty); let coerce_error = self.coerce(provided_arg, checked_ty, coerced_ty, AllowTwoPhase::Yes, None).err(); @@ -541,7 +542,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ty::FnDef(..) => { let fn_ptr = Ty::new_fn_ptr(self.tcx, arg_ty.fn_sig(self.tcx)); - let fn_ptr = self.resolve_vars_if_possible(fn_ptr).to_string(); + let fn_ptr = self.deeply_resolve_ignoring_regions(fn_ptr).to_string(); let fn_item_spa = arg.span; tcx.sess.dcx().emit_err(diagnostics::PassFnItemToVariadicFunction { @@ -572,7 +573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .copied() .zip_eq(expected_input_tys.iter().copied()) - .map(|vars| self.resolve_vars_if_possible(vars)), + .map(|vars| self.deeply_resolve_ignoring_regions(vars)), ); self.report_arg_errors( @@ -652,7 +653,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let formal_input_tupled_ty = formal_input_tys[first_tupled_arg_index_usz]; // Keep the type variable if the argument is splatted, so we can force it to be a tuple later. let tuple_type = if tuple_arguments.is_splatted() { - let callee_tuple_type = self.resolve_vars_with_obligations(formal_input_tupled_ty); + let callee_tuple_type = + self.deeply_resolve_ignoring_regions_with_obligations(formal_input_tupled_ty); if callee_tuple_type.is_ty_var() && let Some(tupled_args_count) = tupled_args_count { @@ -1833,7 +1835,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param.param.span(), format!( "this parameter needs to match the {} type of {deps_list}", - self.resolve_vars_if_possible( + self.deeply_resolve_ignoring_regions( formal_and_expected_inputs[param.deps[0]].1 ) .sort_string(self.tcx), @@ -1857,7 +1859,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!( "{deps_list} need{} to match the {} type of this parameter", pluralize!((deps.len() != 1) as u32), - self.resolve_vars_if_possible(expected_ty) + self.deeply_resolve_ignoring_regions(expected_ty) .sort_string(self.tcx), ), ); @@ -2036,7 +2038,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let expected_display_type = self - .resolve_vars_if_possible(formal_and_expected_inputs[idx].1) + .deeply_resolve_ignoring_regions(formal_and_expected_inputs[idx].1) .sort_string(self.tcx); let label = if idxs_matched == params_with_generics.len() - 1 { format!( @@ -3331,7 +3333,7 @@ impl<'a, 'tcx> ArgsCtxt<'a, 'tcx> { .expr_ty_adjusted_opt(expr) .unwrap_or_else(|| Ty::new_misc_error(self.call_ctxt.fn_ctxt.tcx)); ( - self.call_ctxt.fn_ctxt.resolve_vars_if_possible(ty), + self.call_ctxt.fn_ctxt.deeply_resolve_ignoring_regions(ty), self.normalize_span(expr.span), ) }) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index 8b76a5eb44db7..ee9ebfea1fb38 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -139,7 +139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } obligations_for_self_ty.retain_mut(|obligation| { - obligation.predicate = self.resolve_vars_if_possible(obligation.predicate); + obligation.predicate = self.deeply_resolve_ignoring_regions(obligation.predicate); !obligation.predicate.has_placeholders() }); obligations_for_self_ty diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 3e2c2e8cc3944..d565bc63e0e47 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -262,8 +262,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { found_type: Ty<'tcx>, ) -> bool { let tcx = self.tcx; - let expected = self.resolve_vars_if_possible(expected_type); - let found = self.resolve_vars_if_possible(found_type); + let expected = self.deeply_resolve_ignoring_regions(expected_type); + let found = self.deeply_resolve_ignoring_regions(found_type); if expected.references_error() || found.references_error() || expected.is_unit() { return false; @@ -992,7 +992,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let found = - self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found)); + self.resolve_numeric_literals_with_default(self.deeply_resolve_ignoring_regions(found)); // Only suggest changing the return type for methods that // haven't set a return type at all (and aren't `fn main()`, impl or closure). match &fn_decl.output { @@ -1322,7 +1322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !expected.is_unit() { return; } - let found = self.resolve_vars_if_possible(found); + let found = self.deeply_resolve_ignoring_regions(found); let innermost_loop = if self.is_loop(id) { Some(self.tcx.hir_node(id)) diff --git a/compiler/rustc_hir_typeck/src/inline_asm.rs b/compiler/rustc_hir_typeck/src/inline_asm.rs index e0fccce9577eb..1303c2c2e9e0f 100644 --- a/compiler/rustc_hir_typeck/src/inline_asm.rs +++ b/compiler/rustc_hir_typeck/src/inline_asm.rs @@ -46,7 +46,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { fn expr_ty(&self, expr: &hir::Expr<'tcx>) -> Ty<'tcx> { let ty = self.fcx.typeck_results.borrow().expr_ty_adjusted(expr); - let ty = self.fcx.resolve_vars_with_obligations(ty); + let ty = self.fcx.deeply_resolve_ignoring_regions_with_obligations(ty); if ty.has_non_region_infer() { Ty::new_misc_error(self.tcx()) } else { @@ -61,7 +61,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { if self.fcx.type_is_sized_modulo_regions(self.fcx.param_env, ty) { return true; } - if let ty::Foreign(..) = self.fcx.resolve_vars_with_obligations(ty).kind() { + if let ty::Foreign(..) = + self.fcx.deeply_resolve_ignoring_regions_with_obligations(ty).kind() + { return true; } false diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 6e6ded6c59ea1..c0aa8b8f55c65 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -2147,8 +2147,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { for nested_obligation in candidate.nested_obligations() { if !self.infcx.predicate_may_hold(&nested_obligation) { possibly_unsatisfied_predicates.push(( - self.resolve_vars_if_possible(nested_obligation.predicate), - Some(self.resolve_vars_if_possible(obligation.predicate)), + self.deeply_resolve_ignoring_regions( + nested_obligation.predicate, + ), + Some( + self.deeply_resolve_ignoring_regions( + obligation.predicate, + ), + ), Some(nested_obligation.cause), )); } @@ -2198,9 +2204,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // Evaluate those obligations to see if they might possibly hold. for error in ocx.try_evaluate_obligations() { result = ProbeResult::NoMatch; - let nested_predicate = self.resolve_vars_if_possible(error.obligation.predicate); + let nested_predicate = + self.deeply_resolve_ignoring_regions(error.obligation.predicate); if let Some(trait_predicate) = trait_predicate - && nested_predicate == self.resolve_vars_if_possible(trait_predicate) + && nested_predicate == self.deeply_resolve_ignoring_regions(trait_predicate) { // Don't report possibly unsatisfied predicates if the root // trait obligation from a `TraitCandidate` is unsatisfied. @@ -2208,7 +2215,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } else { possibly_unsatisfied_predicates.push(( nested_predicate, - Some(self.resolve_vars_if_possible(error.root_obligation.predicate)) + Some(self.deeply_resolve_ignoring_regions(error.root_obligation.predicate)) .filter(|root_predicate| *root_predicate != nested_predicate), Some(error.obligation.cause), )); @@ -2329,7 +2336,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { return false; } - !self.resolve_vars_if_possible(self_ty).is_ty_var() + !self.deeply_resolve_ignoring_regions(self_ty).is_ty_var() }); if constrained_opaque { debug!("opaque type has been constrained"); diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index e59ca32aba116..f5158dcdfb998 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1252,7 +1252,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { within_macro_span: Option, ) -> ErrorGuaranteed { let tcx = self.tcx; - let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty); + let rcvr_ty = self.deeply_resolve_ignoring_regions(rcvr_ty); if let Err(guar) = rcvr_ty.error_reported() { return guar; @@ -2254,7 +2254,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("{item_kind} `{item_name}` is available on `{prev_match}`"), ); } - let rcvr_ty = self.resolve_vars_if_possible( + let rcvr_ty = self.deeply_resolve_ignoring_regions( self.typeck_results .borrow() .expr_ty_adjusted_opt(rcvr_expr) @@ -3305,7 +3305,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let field_ty = field.ty(tcx, args).skip_norm_wip(); // Skip `_`, since that'll just lead to ambiguity. - if self.resolve_vars_if_possible(field_ty).is_ty_var() { + if self.deeply_resolve_ignoring_regions(field_ty).is_ty_var() { return None; } @@ -3325,7 +3325,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(ret_ty) = self .ret_coercion .as_ref() - .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty())) + .map(|c| self.deeply_resolve_ignoring_regions(c.borrow().expected_ty())) && let ty::Adt(kind, _) = ret_ty.kind() && tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did()) { @@ -3881,7 +3881,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return_type: Option>, ) { let Some(output_ty) = self.tcx.get_impl_future_output_ty(ty) else { return }; - let output_ty = self.resolve_vars_if_possible(output_ty); + let output_ty = self.deeply_resolve_ignoring_regions(output_ty); let method_exists = self.method_exists_for_diagnostic(item_name, output_ty, call.hir_id, return_type); debug!("suggest_await_before_method: is_method_exist={}", method_exists); diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index c28976555432b..d5e4da7e4250e 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -221,7 +221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr(lhs_expr) } }; - let lhs_ty = self.resolve_vars_with_obligations(lhs_ty); + let lhs_ty = self.deeply_resolve_ignoring_regions_with_obligations(lhs_ty); // N.B., as we have not yet type-checked the RHS, we don't have the // type at hand. Make a variable to represent it. The whole reason @@ -256,7 +256,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }, ); - let rhs_ty = self.resolve_vars_with_obligations(rhs_ty); + let rhs_ty = self.deeply_resolve_ignoring_regions_with_obligations(rhs_ty); let return_ty = self.overloaded_binop_ret_ty( expr, lhs_expr, rhs_expr, op, expected, lhs_ty, result, rhs_ty, @@ -979,7 +979,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { method.sig.output() } Err(errors) => { - let actual = self.resolve_vars_if_possible(operand_ty); + let actual = self.deeply_resolve_ignoring_regions(operand_ty); let guar = actual.error_reported().err().unwrap_or_else(|| { let mut file = None; let ty_str = self.tcx.short_string(actual, &mut file); diff --git a/compiler/rustc_hir_typeck/src/opaque_types.rs b/compiler/rustc_hir_typeck/src/opaque_types.rs index 17e193d7f44ab..a563cf374fddd 100644 --- a/compiler/rustc_hir_typeck/src/opaque_types.rs +++ b/compiler/rustc_hir_typeck/src/opaque_types.rs @@ -93,7 +93,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { error_on_missing_defining_use: bool, ) { for entry in opaque_types.iter_mut() { - *entry = self.resolve_vars_if_possible(*entry); + *entry = self.deeply_resolve_ignoring_regions(*entry); } debug!(?opaque_types); diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 7413215b15ba1..432ade94f49d8 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -497,7 +497,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expected = if let AdjustMode::Peel { .. } = adjust_mode && pat.default_binding_modes { - self.resolve_vars_with_obligations(expected) + self.deeply_resolve_ignoring_regions_with_obligations(expected) } else { expected }; @@ -791,14 +791,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lt.kind ); } - // Call `resolve_vars_if_possible` here for inline const blocks. - let lit_ty = self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)); + // Call `deeply_resolve_ignoring_regions` here for inline const blocks. + let lit_ty = self.deeply_resolve_ignoring_regions(self.check_pat_expr_unadjusted(lt)); // If `deref_patterns` is enabled, allow `if let "foo" = &&"foo" {}`. if self.tcx.features().deref_patterns() { let mut peeled_ty = lit_ty; let mut pat_ref_layers = 0; while let ty::Ref(_, inner_ty, mutbl) = - *self.resolve_vars_with_obligations(peeled_ty).kind() + *self.deeply_resolve_ignoring_regions_with_obligations(peeled_ty).kind() { // We rely on references at the head of constants being immutable. debug_assert!(mutbl.is_not()); @@ -944,7 +944,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match *expected.kind() { // Allow `b"...": &[u8]` ty::Ref(_, inner_ty, _) - if self.resolve_vars_with_obligations(inner_ty).is_slice() => + if self + .deeply_resolve_ignoring_regions_with_obligations(inner_ty) + .is_slice() => { trace!(?expr.hir_id.local_id, "polymorphic byte string lit"); pat_ty = Ty::new_imm_ref( @@ -973,7 +975,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // string literal patterns to have type `str`. This is accounted for when lowering to MIR. if self.tcx.features().deref_patterns() && matches!(lit_kind, ast::LitKind::Str(..)) - && self.resolve_vars_with_obligations(expected).is_str() + && self.deeply_resolve_ignoring_regions_with_obligations(expected).is_str() { pat_ty = self.tcx.types.str_; } @@ -991,7 +993,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let cause = self.pattern_cause(ti, span); if let Err(mut err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) { // If scrutinee is String and pattern is &str, suggest .as_str() - let expected = self.resolve_vars_with_obligations(expected); + let expected = self.deeply_resolve_ignoring_regions_with_obligations(expected); if let ty::Adt(adt, _) = expected.kind() && self.tcx.is_lang_item(adt.did(), LangItem::String) && pat_ty.is_ref() @@ -1029,7 +1031,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // be peeled to `str` while ty here is still `&str`, if we don't // err early here, a rather confusing unification error will be // emitted instead). - let ty = self.resolve_vars_with_obligations(ty); + let ty = self.deeply_resolve_ignoring_regions_with_obligations(ty); let fail = !(ty.is_numeric() || ty.is_char() || ty.is_ty_var() || ty.references_error()); Some((fail, ty, expr.span)) @@ -1108,13 +1110,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "only `char` and numeric types are allowed in range patterns" ); let msg = |ty| { - let ty = self.resolve_vars_if_possible(ty); + let ty = self.deeply_resolve_ignoring_regions(ty); format!("this is of type `{ty}` but it should be `char` or numeric") }; let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| { err.span_label(first_span, msg(first_ty)); if let Some((_, ty, sp)) = second { - let ty = self.resolve_vars_if_possible(ty); + let ty = self.deeply_resolve_ignoring_regions(ty); self.endpoint_has_type(&mut err, sp, ty); } }; @@ -1290,7 +1292,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let var_ty = self.local_ty(span, var_id); if let Err(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) { - let var_ty = self.resolve_vars_if_possible(var_ty); + let var_ty = self.deeply_resolve_ignoring_regions(var_ty); let msg = format!("first introduced with type `{var_ty}` here"); err.span_label(self.tcx.hir_span(var_id), msg); let in_match = self.tcx.hir_parent_iter(var_id).any(|(_, n)| { @@ -1308,7 +1310,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &mut err, span, var_ty, - self.resolve_vars_if_possible(ty), + self.deeply_resolve_ignoring_regions(ty), ba, ); err.emit(); @@ -2734,7 +2736,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { [source_ty], ); let target_ty = self.normalize(span, Unnormalized::new_wip(target_ty)); - self.resolve_vars_with_obligations(target_ty) + self.deeply_resolve_ignoring_regions_with_obligations(target_ty) } /// Check if the interior of a deref pattern (either explicit or implicit) has any `ref mut` @@ -2782,7 +2784,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(pat_prefix_span); } - expected = self.resolve_vars_with_obligations(expected); + expected = self.deeply_resolve_ignoring_regions_with_obligations(expected); // Determine whether we're consuming an inherited reference and resetting the default // binding mode, based on edition and enabled experimental features. if let ByRef::Yes(inh_pin, inh_mut) = pat_info.binding_mode @@ -3073,7 +3075,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { - let expected = self.resolve_vars_with_obligations(expected); + let expected = self.deeply_resolve_ignoring_regions_with_obligations(expected); // If the pattern is irrefutable and `expected` is an infer ty, we try to equate it // to an array if the given pattern allows it. See issue #76342 @@ -3251,7 +3253,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Some(span) = ti.span && let Some(_) = ti.origin_expr { - let resolved_ty = self.resolve_vars_if_possible(ti.expected); + let resolved_ty = self.deeply_resolve_ignoring_regions(ti.expected); let (is_slice_or_array_or_vector, resolved_ty) = self.is_slice_or_array_or_vector(resolved_ty); match resolved_ty.kind() { diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index b3ac237adf956..56112235d3d24 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -74,7 +74,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, base_expr: &hir::Expr<'_>, ) -> Option<(Ty<'tcx>, Ty<'tcx>)> { - let ty = self.resolve_vars_if_possible(ty); + let ty = self.deeply_resolve_ignoring_regions(ty); let mut err = self.dcx().struct_span_err( span, format!("negative integers cannot be used to index on a `{ty}`"), diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 167cb1f272533..e9f7cf1e7783e 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -271,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } }; - let args = self.resolve_vars_if_possible(args); + let args = self.deeply_resolve_ignoring_regions(args); let closure_def_id = closure_def_id.expect_local(); assert_eq!(self.tcx.hir_body_owner_def_id(body.id()), closure_def_id); @@ -1329,7 +1329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let root_var_min_capture_list = min_captures.and_then(|m| m.get(&var_hir_id))?; - let ty = self.resolve_vars_if_possible(self.node_ty(var_hir_id)); + let ty = self.deeply_resolve_ignoring_regions(self.node_ty(var_hir_id)); let ty = match closure_clause { hir::CaptureBy::Value { .. } => ty, // For move closure the capture kind should be by value @@ -1427,7 +1427,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { closure_clause: hir::CaptureBy, var_hir_id: HirId, ) -> Option> { - let ty = self.resolve_vars_if_possible(self.node_ty(var_hir_id)); + let ty = self.deeply_resolve_ignoring_regions(self.node_ty(var_hir_id)); // FIXME(#132279): Using `non_body_analysis` here feels wrong. if !ty.has_significant_drop( diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index b71290b658744..f4fe38924351a 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -807,8 +807,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let obligations = self.fcx.take_hir_typeck_potentially_region_dependent_goals(); if self.fcx.tainted_by_errors().is_none() { for obligation in obligations { - let (predicate, mut cause) = - self.fcx.resolve_vars_if_possible((obligation.predicate, obligation.cause)); + let (predicate, mut cause) = self + .fcx + .deeply_resolve_ignoring_regions((obligation.predicate, obligation.cause)); if predicate.has_non_region_infer() { self.fcx.dcx().span_delayed_bug( cause.span, @@ -833,7 +834,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { where T: TypeFoldable>, { - let value = self.fcx.resolve_vars_if_possible(value); + let value = self.fcx.deeply_resolve_ignoring_regions(value); let mut goals = vec![]; let value = @@ -847,7 +848,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { goals .into_iter() .map(|pred| { - self.fcx.resolve_vars_if_possible(pred).fold_with(&mut Resolver::new( + self.fcx.deeply_resolve_ignoring_regions(pred).fold_with(&mut Resolver::new( self.fcx, span, self.body, @@ -876,7 +877,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { where T: TypeFoldable>, { - let value = self.fcx.resolve_vars_if_possible(value); + let value = self.fcx.deeply_resolve_ignoring_regions(value); let mut goals = vec![]; let value = diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index f9b08efad88cf..8b84be5d1ffae 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -278,11 +278,11 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.shallow_resolve_const(ct) } - fn resolve_vars_if_possible(&self, value: T) -> T + fn deeply_resolve_ignoring_regions(&self, value: T) -> T where T: TypeFoldable>, { - self.resolve_vars_if_possible(value) + self.deeply_resolve_ignoring_regions(value) } fn probe(&self, probe: impl FnOnce() -> T) -> T { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 56fcc72bd9769..b6b733c2c68da 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1223,7 +1223,7 @@ impl<'tcx> InferCtxt<'tcx> { } pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { - self.resolve_vars_if_possible(t).to_string() + self.deeply_resolve_ignoring_regions(t).to_string() } /// If `TyVar(vid)` resolves to a type, return that type. Else, return the @@ -1399,13 +1399,13 @@ impl<'tcx> InferCtxt<'tcx> { } } - /// Where possible, replaces type/const variables in - /// `value` with their final value. Note that region variables - /// are unaffected. If a type/const variable has not been unified, it - /// is left as is. This is an idempotent operation that does - /// not affect inference state in any way and so you can do it - /// at will. - pub fn resolve_vars_if_possible(&self, value: T) -> T + /// If a type/const variable has not (yet) been unified, it is left as is. + /// + /// This is an idempotent operation that does not affect inference state in any way, + /// which means it's safe to call this function at will. + /// + /// Region variables are unaffected. + pub fn deeply_resolve_ignoring_regions(&self, value: T) -> T where T: TypeFoldable>, { @@ -1415,7 +1415,7 @@ impl<'tcx> InferCtxt<'tcx> { if !value.has_non_region_infer() { return value; } - let mut r = resolve::OpportunisticVarResolver::new(self); + let mut r = resolve::DeepResolverIgnoringRegions::new(self); value.fold_with(&mut r) } diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 70423ca7da1be..38a430931b250 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -166,7 +166,7 @@ impl<'tcx> InferCtxt<'tcx> { } else if let Some(res) = process(b, a) { res } else { - let (a, b) = self.resolve_vars_if_possible((a, b)); + let (a, b) = self.deeply_resolve_ignoring_regions((a, b)); Err(TypeError::Sorts(ExpectedFound::new(a, b))) } } diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 473b476ce8697..20bf987e07d0c 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -36,7 +36,7 @@ impl<'tcx> InferCtxt<'tcx> { /// Process the region constraints and return any errors that /// result. After this, no more unification operations should be /// done -- or the compiler will panic -- but it is legal to use - /// `resolve_vars_if_possible` as well as `fully_resolve`. + /// `deeply_resolve_ignoring_regions` as well as `fully_resolve`. /// /// Don't call this directly unless you know what you're doing. /// You probably want to use `resolve_regions` instead. diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index a6c610edebf02..ff9d66588fe78 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -66,7 +66,7 @@ use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::outlives::{Component, push_outlives_components}; use rustc_middle::ty::{ self, GenericArgKind, GenericArgsRef, PolyTypeOutlivesClause, Region, RegionVid, Ty, TyCtxt, - TypeVisitableExt, Upcast, eager_resolve_vars, + TypeVisitableExt, Upcast, deeply_resolve_via_unification_table, }; use rustc_span::Span; use rustc_type_ir::region_constraint::{self, LeafRegionConstraint}; @@ -371,7 +371,7 @@ impl<'tcx> InferCtxt<'tcx> { // `TypeOutlives` is structural, so we should try to opportunistically resolve all // region vids before processing regions, so we have a better chance to match clauses // in our param-env. - let (sup_type, sub_region) = eager_resolve_vars(self, (sup_type, sub_region)); + let (sup_type, sub_region) = deeply_resolve_via_unification_table(self, (sup_type, sub_region)); if self.tcx.sess.opts.unstable_opts.higher_ranked_assumptions && outlives_env diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index db4f313903a5a..2b92c9b587bdf 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -9,28 +9,28 @@ use super::{FixupError, FixupResult, InferCtxt}; use crate::infer::TyOrConstInferVar; /////////////////////////////////////////////////////////////////////////// -// OPPORTUNISTIC VAR RESOLVER +// DEEP VAR RESOLVER -/// The opportunistic resolver can be used at any time. It simply replaces +/// The type and const resolver can be used at any time. It simply replaces /// type/const variables that have been unified with the things they have /// been unified with (similar to `shallow_resolve`, but deep). This is /// useful for printing messages etc but also required at various /// points for correctness. -pub struct OpportunisticVarResolver<'a, 'tcx> { +pub struct DeepResolverIgnoringRegions<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, /// We're able to use a cache here as the folder does /// not have any mutable state. cache: DelayedMap, Ty<'tcx>>, } -impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> { +impl<'a, 'tcx> DeepResolverIgnoringRegions<'a, 'tcx> { #[inline] pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { - OpportunisticVarResolver { infcx, cache: Default::default() } + DeepResolverIgnoringRegions { infcx, cache: Default::default() } } } -impl<'a, 'tcx> TypeFolder> for OpportunisticVarResolver<'a, 'tcx> { +impl<'a, 'tcx> TypeFolder> for DeepResolverIgnoringRegions<'a, 'tcx> { fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -67,24 +67,24 @@ impl<'a, 'tcx> TypeFolder> for OpportunisticVarResolver<'a, 'tcx> { } } -/// The opportunistic region resolver opportunistically resolves regions -/// variables to the variable with the least variable id. It is used when -/// normalizing projections to avoid hitting the recursion limit by creating -/// many versions of a predicate for types that in the end have to unify. +/// The region resolver resolves region variables to the variable with the +/// least variable id. It is used when normalizing projections to avoid +/// hitting the recursion limit by creating many versions of a predicate +/// for types that in the end have to unify. /// /// If you want to resolve type and const variables as well, call -/// [InferCtxt::resolve_vars_if_possible] first. -pub struct OpportunisticRegionResolver<'a, 'tcx> { +/// [InferCtxt::deeply_resolve_ignoring_regions] first. +pub struct DeepRegionResolver<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, } -impl<'a, 'tcx> OpportunisticRegionResolver<'a, 'tcx> { +impl<'a, 'tcx> DeepRegionResolver<'a, 'tcx> { pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { - OpportunisticRegionResolver { infcx } + DeepRegionResolver { infcx } } } -impl<'a, 'tcx> TypeFolder> for OpportunisticRegionResolver<'a, 'tcx> { +impl<'a, 'tcx> TypeFolder> for DeepRegionResolver<'a, 'tcx> { fn cx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs index 2ce98b7541afa..98ac3f4376c2c 100644 --- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs +++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs @@ -111,7 +111,7 @@ impl<'tcx> InferCtxt<'tcx> { // going to be popped, so we will have to // eliminate any references to them. let snapshot_vars = SnapshotVarData::new(self, variable_lengths); - Ok((snapshot_vars, self.resolve_vars_if_possible(value))) + Ok((snapshot_vars, self.deeply_resolve_ignoring_regions(value))) })?; // At this point, we need to replace any of the now-popped diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index 0d8620c3614a2..c8e880cf8a7dc 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -19,7 +19,7 @@ use rustc_type_ir::relate::{ }; use rustc_type_ir::{ self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner, Region, - TypeFoldable, TypingMode, TypingModeEqWrapper, eager_resolve_vars, + TypeFoldable, TypingMode, TypingModeEqWrapper, deeply_resolve_via_unification_table, }; use thin_vec::ThinVec; use tracing::instrument; @@ -568,7 +568,7 @@ where { let var_values = CanonicalVarValues { var_values: delegate.cx().mk_args(var_values) }; let state = inspect::State { var_values, data }; - let state = eager_resolve_vars(&**delegate, state); + let state = deeply_resolve_via_unification_table(&**delegate, state); Canonicalizer::canonicalize_response(delegate, max_input_universe, state) } diff --git a/compiler/rustc_next_trait_solver/src/normalize.rs b/compiler/rustc_next_trait_solver/src/normalize.rs index 1fd62213b735a..8145be2ed2c7f 100644 --- a/compiler/rustc_next_trait_solver/src/normalize.rs +++ b/compiler/rustc_next_trait_solver/src/normalize.rs @@ -3,7 +3,7 @@ use std::fmt::Debug; use rustc_type_ir::inherent::*; use rustc_type_ir::{ self as ty, AliasTerm, Binder, FallibleTypeFolder, InferCtxtLike, Interner, PredicateProxy, - TypeFoldable, TypeSuperFoldable, TypeVisitableExt, UniverseIndex, eager_resolve_vars, + TypeFoldable, TypeSuperFoldable, TypeVisitableExt, UniverseIndex, deeply_resolve_via_unification_table, }; use tracing::instrument; @@ -139,8 +139,8 @@ where if self.cx().renormalize_rigid_aliases() && orig_is_rigid == ty::IsRigid::Yes { // find out missing typing env change. - let original = eager_resolve_vars(infcx, original); - let normalized = eager_resolve_vars(infcx, normalized); + let original = deeply_resolve_via_unification_table(infcx, original); + let normalized = deeply_resolve_via_unification_table(infcx, normalized); assert_eq!(original, normalized, "rigid alias is further normalized"); } Ok(normalized) @@ -189,8 +189,8 @@ where if self.cx().renormalize_rigid_aliases() && orig_is_rigid == ty::IsRigid::Yes { // find out missing typing env change. - let original = eager_resolve_vars(infcx, original); - let normalized = eager_resolve_vars(infcx, normalized); + let original = deeply_resolve_via_unification_table(infcx, original); + let normalized = deeply_resolve_via_unification_table(infcx, normalized); assert_eq!(original, normalized, "rigid alias is further normalized"); } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 51e1aea3850e4..bc8bdc085cddb 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -464,7 +464,7 @@ where // Vars that show up in the rest of the goal substs may have been constrained by // normalizing the self type as well, since type variables are not uniquified. - let goal = self.resolve_vars_if_possible(goal); + let goal = self.deeply_resolve_ignoring_regions(goal); if self.typing_mode().is_coherence() && let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index ae5cf61aac91e..825105bddd380 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -19,8 +19,8 @@ use rustc_type_ir::solve::{ use rustc_type_ir::{ self as ty, CanonicalVarValues, ClauseKind, InferCtxtLike, Interner, MayBeErased, OpaqueTypeKey, PredicateKind, PredicateProxy, Region, RegionVid, TypeFoldable, - TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, - eager_resolve_vars, max_universe, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, deeply_resolve_via_unification_table, + max_universe, }; use thin_vec::ThinVec; use tracing::{Level, debug, instrument, trace, warn}; @@ -659,7 +659,7 @@ where // so we only canonicalize the lookup table and ignore // duplicate entries. let opaque_types = self.delegate.clone_opaque_types_lookup_table(); - let (goal, opaque_types) = eager_resolve_vars(&**self.delegate, (goal, opaque_types)); + let (goal, opaque_types) = deeply_resolve_via_unification_table(&**self.delegate, (goal, opaque_types)); let typing_mode = self.typing_mode(); let step_kind = self.step_kind_for_source(source); @@ -1300,11 +1300,11 @@ where }) } - pub(super) fn resolve_vars_if_possible(&self, value: T) -> T + pub(super) fn deeply_resolve_ignoring_regions(&self, value: T) -> T where T: TypeFoldable, { - self.delegate.resolve_vars_if_possible(value) + self.delegate.deeply_resolve_ignoring_regions(value) } pub(super) fn shallow_resolve(&self, ty: I::Ty) -> I::Ty { @@ -1432,14 +1432,14 @@ where self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } None if self.cx().features().generic_const_args() => { - // HACK(khyperia): calling `resolve_vars_if_possible` here shouldn't be necessary, - // `try_evaluate_const` calls `resolve_vars_if_possible` already. However, we want + // HACK(khyperia): calling `deeply_resolve_ignoring_regions` here shouldn't be necessary, + // `try_evaluate_const` calls `deeply_resolve_ignoring_regions` already. However, we want // to check `has_non_region_infer` against the type with vars resolved (i.e. check // if there are vars we failed to resolve), so we need to call it again here. // Perhaps we could split EvaluateConstErr::HasGenericsOrInfers into HasGenerics and // HasInfers or something, make evaluate_const return that, and make this branch be // based on that, rather than checking `has_non_region_infer`. - if self.resolve_vars_if_possible(alias_const).has_non_region_infer() { + if self.deeply_resolve_ignoring_regions(alias_const).has_non_region_infer() { self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } else { // Evaluation failed because the const was too generic or was an invalid type @@ -1605,7 +1605,7 @@ where let external_constraints = self.compute_external_query_constraints(certainty, normalization_nested_goals); let (var_values, mut external_constraints) = - eager_resolve_vars(&**self.delegate, (self.var_values, external_constraints)); + deeply_resolve_via_unification_table(&**self.delegate, (self.var_values, external_constraints)); // Remove any trivial or duplicated region constraints once we've resolved regions let mut unique = HashSet::default(); @@ -1772,7 +1772,7 @@ where param_env: I::ParamEnv, value: ty::Unnormalized, ) -> Result { - let value = self.delegate.resolve_vars_if_possible(value.skip_normalization()); + let value = self.delegate.deeply_resolve_ignoring_regions(value.skip_normalization()); if !self.cx().renormalize_rigid_aliases() && !value.has_non_rigid_aliases() { return Ok(value); @@ -1795,7 +1795,7 @@ where } }; - Ok((self.resolve_vars_if_possible(infer_term), normalization_was_ambiguous)) + Ok((self.deeply_resolve_ignoring_regions(infer_term), normalization_was_ambiguous)) }); value.try_fold_with(&mut folder) } @@ -1929,7 +1929,7 @@ pub(super) fn evaluate_root_goal_for_proof_tree, root_depth: usize, ) -> (Result, NoSolution>, inspect::GoalEvaluation) { let opaque_types = delegate.clone_opaque_types_lookup_table(); - let (goal, opaque_types) = eager_resolve_vars(&**delegate, (goal, opaque_types)); + let (goal, opaque_types) = deeply_resolve_via_unification_table(&**delegate, (goal, opaque_types)); let typing_mode = delegate.typing_mode_raw().assert_not_erased(); let (orig_values, canonical_goal) = diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 8d20bcf4c7a6d..10ee038005d8e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -404,7 +404,7 @@ where // types from candidates. self.add_goal(GoalSource::TypeRelating, projection_goal)?; self.try_evaluate_added_goals()?; - Ok(self.resolve_vars_if_possible(normalized_term)) + Ok(self.deeply_resolve_ignoring_regions(normalized_term)) } else { Ok(term) } diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 51ec0bcbf5ec2..294c887b5062c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -1114,7 +1114,7 @@ where return Ok(false); } match ecx.probe(|_| ProbeKind::ProjectionCompatibility).enter(|ecx| { - let target_projection = ecx.resolve_vars_if_possible(target_projection); + let target_projection = ecx.deeply_resolve_ignoring_regions(target_projection); ecx.enter_forall_with_assumptions( target_projection, param_env, @@ -1141,7 +1141,8 @@ where let source_principal = upcast_principal.unwrap(); let target_principal = bound.rebind(target_principal); // We might unify infer vars in previous iterations. - let target_principal = ecx.resolve_vars_if_possible(target_principal); + let target_principal = + ecx.deeply_resolve_ignoring_regions(target_principal); ecx.enter_forall_with_assumptions( target_principal, param_env, @@ -1176,7 +1177,8 @@ where }; // We might unify infer vars in previous iterations. - let target_projection = ecx.resolve_vars_if_possible(target_projection); + let target_projection = + ecx.deeply_resolve_ignoring_regions(target_projection); ecx.enter_forall_with_assumptions( target_projection, param_env, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 3e7b3d2ae2daa..406349b621958 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -130,7 +130,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let ocx = ObligationCtxt::new(self); let normalized_fn_sig = ocx.normalize(&ObligationCause::dummy(), param_env, fn_sig); if ocx.evaluate_obligations_error_on_ambiguity().no_errors() { - let normalized_fn_sig = self.resolve_vars_if_possible(normalized_fn_sig); + let normalized_fn_sig = self.deeply_resolve_ignoring_regions(normalized_fn_sig); if !normalized_fn_sig.has_infer() { return normalized_fn_sig; } @@ -158,7 +158,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { where M: FnOnce(String) -> Diag<'a>, { - let actual_ty = self.resolve_vars_if_possible(actual_ty); + let actual_ty = self.deeply_resolve_ignoring_regions(actual_ty); debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty); let mut err = mk_diag(self.ty_to_string(actual_ty)); @@ -336,7 +336,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span: Some(span), root_ty, } => { - let expected_ty = self.resolve_vars_if_possible(root_ty); + let expected_ty = self.deeply_resolve_ignoring_regions(root_ty); if !matches!( expected_ty.kind(), ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_)) @@ -466,7 +466,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } _ => { // `prior_arm_ty` can be `!`, `expected` will have better info when present. - let t = self.resolve_vars_if_possible(match exp_found { + let t = self.deeply_resolve_ignoring_regions(match exp_found { Some(ty::error::ExpectedFound { expected, .. }) => expected, _ => prior_arm_ty, }); @@ -1576,7 +1576,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let (expected_found, exp_found, is_simple_error, values, param_env) = match values { None => (None, Mismatch::Fixed("type"), false, None, None), Some(ty::ParamEnvAnd { param_env, value: values }) => { - let values = self.resolve_vars_if_possible(values); + let values = self.deeply_resolve_ignoring_regions(values); let (is_simple_error, exp_found) = match values { ValuePairs::Terms(ExpectedFound { expected, found }) => { match (expected.kind(), found.kind()) { @@ -1988,7 +1988,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) -> Vec { let mut suggestions = Vec::new(); let span = trace.cause.span; - let values = self.resolve_vars_if_possible(trace.values); + let values = self.deeply_resolve_ignoring_regions(trace.values); if let Some((expected, found)) = values.ty() { match (expected.kind(), found.kind()) { (ty::Tuple(_), ty::Tuple(_)) => {} @@ -2344,7 +2344,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } ValuePairs::PolySigs(exp_found) => { - let exp_found = self.resolve_vars_if_possible(exp_found); + let exp_found = self.deeply_resolve_ignoring_regions(exp_found); if exp_found.references_error() { return None; } @@ -2369,7 +2369,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { exp_found: ty::error::ExpectedFound>, long_ty_path: &mut Option, ) -> Option<(DiagStyledString, DiagStyledString)> { - let exp_found = self.resolve_vars_if_possible(exp_found); + let exp_found = self.deeply_resolve_ignoring_regions(exp_found); if exp_found.references_error() { return None; } @@ -2441,7 +2441,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &self, exp_found: ty::error::ExpectedFound, ) -> Option<(DiagStyledString, DiagStyledString)> { - let exp_found = self.resolve_vars_if_possible(exp_found); + let exp_found = self.deeply_resolve_ignoring_regions(exp_found); if exp_found.references_error() { return None; } @@ -2467,7 +2467,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// FloatVar inference type are compatible with themselves or their concrete types (Int and /// Float types, respectively). When comparing two ADTs, these rules apply recursively. pub fn same_type_modulo_infer>>(&self, a: T, b: T) -> bool { - let (a, b) = self.resolve_vars_if_possible((a, b)); + let (a, b) = self.deeply_resolve_ignoring_regions((a, b)); SameTypeModuloInfer(self).relate(a, b).is_ok() } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 903c3998fd4b6..664bd9b66bbc4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -88,7 +88,7 @@ impl InferenceDiagnosticsData { "" } else if self.name == "_" { let displayed_ty = infcx - .resolve_vars_if_possible(in_type) + .deeply_resolve_ignoring_regions(in_type) .fold_with(&mut ClosureEraser { infcx, depth: 0 }); if displayed_ty.is_ty_or_numeric_infer() { "" @@ -308,7 +308,7 @@ fn ty_to_string<'tcx>( called_method_def_id: Option, ) -> String { let mut p = fmt_printer(infcx, Namespace::TypeNS); - let ty = infcx.resolve_vars_if_possible(ty); + let ty = infcx.deeply_resolve_ignoring_regions(ty); // We use `fn` ptr syntax for closures, but this only works when the closure does not capture // anything. We also remove all type parameters that are fully known to the type system. let ty = ty.fold_with(&mut ClosureEraser { infcx, depth: 0 }); @@ -507,7 +507,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { should_label_span: bool, ty: Option>, ) -> Diag<'a> { - let term = self.resolve_vars_if_possible(term); + let term = self.deeply_resolve_ignoring_regions(term); let arg_data = self .extract_inference_diagnostics_data(term, ty::print::RegionHighlightMode::default()); @@ -1019,12 +1019,12 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { fn node_args_opt(&self, hir_id: HirId) -> Option> { let args = self.typeck_results.node_args_opt(hir_id); - self.tecx.resolve_vars_if_possible(args) + self.tecx.deeply_resolve_ignoring_regions(args) } fn opt_node_type(&self, hir_id: HirId) -> Option> { let ty = self.typeck_results.node_type_opt(hir_id); - self.tecx.resolve_vars_if_possible(ty) + self.tecx.deeply_resolve_ignoring_regions(ty) } // Check whether this generic argument is the inference variable we @@ -1412,7 +1412,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { .iter() .position(|&arg| self.generic_arg_contains_target(arg)) { - let args = self.tecx.resolve_vars_if_possible(args); + let args = self.tecx.deeply_resolve_ignoring_regions(args); let generic_args = &generics.own_args_no_defaults(tcx, args)[generics.own_counts().lifetimes..]; let span = match expr.kind { @@ -1493,7 +1493,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { { let successor = method_args.get(0).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo())); - let args = self.tecx.resolve_vars_if_possible(args); + let args = self.tecx.deeply_resolve_ignoring_regions(args); self.update_infer_source(InferSource { span: path.ident.span, kind: InferSourceKind::FullyQualifiedMethodCall { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs index 7f07fab6e8474..6b97651d5f968 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -271,16 +271,12 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { (false, None, None, Some(span), String::new()) }; - let expected_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef::new_from_args( - self.cx.tcx, - trait_def_id, - expected_args, - )); - let actual_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef::new_from_args( - self.cx.tcx, - trait_def_id, - actual_args, - )); + let expected_trait_ref = self.cx.deeply_resolve_ignoring_regions( + ty::TraitRef::new_from_args(self.cx.tcx, trait_def_id, expected_args), + ); + let actual_trait_ref = self.cx.deeply_resolve_ignoring_regions( + ty::TraitRef::new_from_args(self.cx.tcx, trait_def_id, actual_args), + ); // Search the expected and actual trait references to see (a) // whether the sub/sup placeholders appear in them (sometimes @@ -400,7 +396,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { // the confusing lifetime-generality error into an actionable hint, e.g.: // |buf| → |buf: &mut [u8]| if self.tcx().is_fn_trait(trait_def_id) { - let actual_self_ty = self.cx.resolve_vars_if_possible( + let actual_self_ty = self.cx.deeply_resolve_ignoring_regions( ty::TraitRef::new_from_args(self.cx.tcx, trait_def_id, actual_args).self_ty(), ); if let ty::Closure(closure_def_id, _) = *actual_self_ty.kind() diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 45ae86b39f35e..b6df361546512 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -990,7 +990,7 @@ fn foo(&self) -> Self::T { String::new() } msg: impl Fn() -> String, is_bound_surely_present: bool, ) -> bool { - // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting. + // FIXME: we would want to call `deeply_resolve_ignoring_regions` on `ty` before suggesting. let trait_bounds = bounds.iter().filter_map(|bound| match bound { hir::GenericBound::Trait(ptr) if ptr.modifiers == hir::TraitBoundModifiers::NONE => { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 73b98b8eda1a6..37076b0b655f2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -430,7 +430,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); self.dcx().create_err(FulfillReqLifetime { span, - ty: self.resolve_vars_if_possible(ty), + ty: self.deeply_resolve_ignoring_regions(ty), note, }) } @@ -495,7 +495,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); self.dcx().create_err(RefLongerThanData { span, - ty: self.resolve_vars_if_possible(ty), + ty: self.deeply_resolve_ignoring_regions(ty), notes: pointer_valid.into_iter().chain(data_valid).collect(), }) } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index db852701051cf..b5235fa443575 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -48,8 +48,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { second_span: Span, ) -> Option { let remove_semicolon = [ - (first_id, self.resolve_vars_if_possible(second_ty)), - (second_id, self.resolve_vars_if_possible(first_ty)), + (first_id, self.deeply_resolve_ignoring_regions(second_ty)), + (second_id, self.deeply_resolve_ignoring_regions(first_ty)), ] .into_iter() .find_map(|(id, ty)| { @@ -926,7 +926,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .as_ref() .and_then(|typeck_results| typeck_results.node_type_opt(*hir_id)) { - let pat_ty = self.resolve_vars_if_possible(pat_ty); + let pat_ty = self.deeply_resolve_ignoring_regions(pat_ty); if self.same_type_modulo_infer(pat_ty, expected_ty) && !(pat_ty, expected_ty).references_error() && shadowed.insert(ident.name) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index 2b7a20c90c87b..a44d53cdfdd05 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -213,7 +213,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // ambiguous impls. The latter *ought* to be a // coherence violation, so we don't report it here. - let predicate = self.resolve_vars_if_possible(obligation.predicate); + let predicate = self.deeply_resolve_ignoring_regions(obligation.predicate); let span = obligation.cause.span; let mut long_ty_path = None; @@ -711,7 +711,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut mentioned = vec![predicate]; let mut mentioned_strs: Vec = vec![]; for &error in related { - let related_pred = self.resolve_vars_if_possible(error.obligation.predicate); + let related_pred = self.deeply_resolve_ignoring_regions(error.obligation.predicate); if mentioned.contains(&related_pred) { continue; } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index d8a22e745bcc2..df0a74cb5ba6e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -111,8 +111,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let bound_predicate = obligation.predicate.kind(); match bound_predicate.skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => { - let leaf_trait_predicate = - self.resolve_vars_if_possible(bound_predicate.rebind(trait_predicate)); + let leaf_trait_predicate = self.deeply_resolve_ignoring_regions( + bound_predicate.rebind(trait_predicate), + ); // Let's use the root obligation as the main message, when we care about the // most general case ("X doesn't implement Pattern<'_>") over the case that @@ -153,7 +154,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && !self.tcx.is_lang_item(root_pred.def_id(), LangItem::Unsize) { ( - self.resolve_vars_if_possible( + self.deeply_resolve_ignoring_regions( root_obligation.predicate.kind().rebind(root_pred), ), root_obligation, @@ -710,7 +711,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => { - let ty = self.resolve_vars_if_possible(ty); + let ty = self.deeply_resolve_ignoring_regions(ty); if self.next_trait_solver() { if let Err(guar) = ty.error_reported() { return guar; @@ -1202,7 +1203,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let noted_missing_impl = self.note_missing_impl_for_question_mark(err, self_ty, found_ty, trait_pred); - let mut prev_ty = self.resolve_vars_if_possible( + let mut prev_ty = self.deeply_resolve_ignoring_regions( typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), ); @@ -1234,7 +1235,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { expr = rcvr_expr; chain.push((span, prev_ty)); - let next_ty = self.resolve_vars_if_possible( + let next_ty = self.deeply_resolve_ignoring_regions( typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), ); @@ -1277,7 +1278,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // The last statement is of a type that can be converted to the return error type && let [.., stmt] = block.stmts && let hir::StmtKind::Semi(expr) = stmt.kind - && let expr_ty = self.resolve_vars_if_possible( + && let expr_ty = self.deeply_resolve_ignoring_regions( typeck.expr_ty_adjusted_opt(expr) .unwrap_or(Ty::new_misc_error(self.tcx)), ) @@ -1322,7 +1323,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // `expr` is now the "root" expression of the method call chain, which can be any // expression kind, like a method call or a path. If this expression is `Result` as // well, then we also point at it. - prev_ty = self.resolve_vars_if_possible( + prev_ty = self.deeply_resolve_ignoring_regions( typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), ); chain.push((expr.span, prev_ty)); @@ -1669,7 +1670,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation: &PredicateObligation<'tcx>, error: &MismatchedProjectionTypes<'tcx>, ) -> ErrorGuaranteed { - let predicate = self.resolve_vars_if_possible(obligation.predicate); + let predicate = self.deeply_resolve_ignoring_regions(obligation.predicate); if let Err(e) = predicate.error_reported() { return e; @@ -1710,7 +1711,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ( Some(( data.projection_term, - self.resolve_vars_if_possible(normalized_term), + self.deeply_resolve_ignoring_regions(normalized_term), data.term, )), new_err, @@ -1737,8 +1738,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ( with_forced_trimmed_paths!(format!( "type mismatch resolving `{}`", - self.tcx - .short_string(self.resolve_vars_if_possible(predicate), &mut file), + self.tcx.short_string( + self.deeply_resolve_ignoring_regions(predicate), + &mut file + ), )), obligation.cause.span, None, @@ -1872,7 +1875,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { with_forced_trimmed_paths!(Cow::from(format!( "type mismatch resolving `{}`", self.tcx.short_string( - self.resolve_vars_if_possible(predicate), + self.deeply_resolve_ignoring_regions(predicate), diag.long_ty_path() ), ))), @@ -2280,7 +2283,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return false; } - let impl_trait_ref = self.resolve_vars_if_possible(impl_trait_ref); + let impl_trait_ref = self.deeply_resolve_ignoring_regions(impl_trait_ref); if impl_trait_ref.references_error() { return false; } @@ -2362,7 +2365,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.highlighted_span_help(self.tcx.def_span(single.impl_def_id), msg); if let [TypeError::Sorts(exp_found)] = &terrs[..] { - let exp_found = self.resolve_vars_if_possible(*exp_found); + let exp_found = self.deeply_resolve_ignoring_regions(*exp_found); let expected = self.tcx.short_string(exp_found.expected, err.long_ty_path()); let found = self.tcx.short_string(exp_found.found, err.long_ty_path()); @@ -2783,7 +2786,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) -> Option<(Ty<'tcx>, Option)> { match code { ObligationCauseCode::BuiltinDerived(data) => { - let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); + let parent_trait_ref = self.deeply_resolve_ignoring_regions(data.parent_trait_pred); match self.get_parent_trait_ref(&data.parent_code) { Some(t) => Some(t), None => { @@ -3117,7 +3120,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { cause_code: &ObligationCauseCode<'tcx>, ) -> bool { if let ObligationCauseCode::BuiltinDerived(data) = cause_code { - let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); + let parent_trait_ref = self.deeply_resolve_ignoring_regions(data.parent_trait_pred); let self_ty = parent_trait_ref.skip_binder().self_ty(); if obligated_types.iter().any(|ot| ot == &self_ty) { return true; @@ -3646,8 +3649,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { found_trait_ref: ty::TraitRef<'tcx>, expected_trait_ref: ty::TraitRef<'tcx>, ) -> Result, ErrorGuaranteed> { - let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref); - let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref); + let found_trait_ref = self.deeply_resolve_ignoring_regions(found_trait_ref); + let expected_trait_ref = self.deeply_resolve_ignoring_regions(expected_trait_ref); expected_trait_ref.self_ty().error_reported()?; let found_trait_ty = found_trait_ref.self_ty(); @@ -3962,7 +3965,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.tcx .fn_trait_kind_from_def_id(trait_def_id) .expect("expected to map DefId to ClosureKind"), - ty.rebind(self.resolve_vars_if_possible(var)), + ty.rebind(self.deeply_resolve_ignoring_regions(var)), )); } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index ab6aa9c58d9c2..b0a513f692c38 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -280,7 +280,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // roots, like `need_type_info` does when looking for the annotation source. let ambiguity_infer_var = |error: &FulfillmentError<'tcx>| match error.code { FulfillmentErrorCode::Ambiguity { overflow: None } => self - .ambiguity_term(self.resolve_vars_if_possible(error.obligation.predicate)) + .ambiguity_term(self.deeply_resolve_ignoring_regions(error.obligation.predicate)) .and_then(|term| { ty::GenericArg::from(term) .walk() diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs index 30a18a928e842..e8765e3b0ad27 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs @@ -77,7 +77,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut err = match cause { OverflowCause::DeeplyNormalize(alias_term) => { - let alias_term = self.resolve_vars_if_possible(alias_term); + let alias_term = self.deeply_resolve_ignoring_regions(alias_term); let kind = alias_term.kind.descr(); let alias_str = with_short_path(self.tcx, alias_term); struct_span_code_err!( @@ -88,7 +88,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) } OverflowCause::TraitSolver(predicate) => { - let predicate = self.resolve_vars_if_possible(predicate); + let predicate = self.deeply_resolve_ignoring_regions(predicate); match predicate.kind().skip_binder() { ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) | ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => { @@ -143,7 +143,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { T: Upcast, ty::Predicate<'tcx>> + Clone, { let predicate = obligation.predicate.clone().upcast(self.tcx); - let predicate = self.resolve_vars_if_possible(predicate); + let predicate = self.deeply_resolve_ignoring_regions(predicate); self.report_overflow_error( OverflowCause::TraitSolver(predicate), obligation.cause.span, @@ -168,7 +168,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// we do not suggest increasing the overflow limit, which is not /// going to help). pub fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! { - let cycle = self.resolve_vars_if_possible(cycle.to_owned()); + let cycle = self.deeply_resolve_ignoring_regions(cycle.to_owned()); assert!(!cycle.is_empty()); debug!(?cycle, "report_overflow_error_cycle"); @@ -186,7 +186,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation: PredicateObligation<'tcx>, suggest_increasing_limit: bool, ) -> ErrorGuaranteed { - let obligation = self.resolve_vars_if_possible(obligation); + let obligation = self.deeply_resolve_ignoring_regions(obligation); let mut err = self.build_overflow_error( OverflowCause::TraitSolver(obligation.predicate), obligation.cause.span, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 2fbc6f16c14d4..92c3e90b7b033 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -82,7 +82,7 @@ impl<'a, 'tcx> CoroutineData<'a, 'tcx> { infer_context.tcx.upvars_mentioned(coroutine_did).and_then(|upvars| { upvars.iter().find_map(|(upvar_id, upvar)| { let upvar_ty = self.0.node_type(*upvar_id); - let upvar_ty = infer_context.resolve_vars_if_possible(upvar_ty); + let upvar_ty = infer_context.deeply_resolve_ignoring_regions(upvar_ty); ty_matches(ty::Binder::dummy(upvar_ty)) .then(|| CoroutineInteriorOrUpvar::Upvar(upvar.span)) }) @@ -328,7 +328,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let Some(base_ty) = typeck_results.expr_ty_opt(base_expr) else { return; }; - let base_ty = self.resolve_vars_if_possible(base_ty); + let base_ty = self.deeply_resolve_ignoring_regions(base_ty); if base_ty.references_error() { return; } @@ -1357,7 +1357,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.span_label(block.span, "this block is missing a tail expression"); return; }; - let ty = self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(ty)); + let ty = + self.resolve_numeric_literals_with_default(self.deeply_resolve_ignoring_regions(ty)); let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, ty)); let new_obligation = @@ -1382,7 +1383,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err: &mut Diag<'_>, trait_pred: ty::PolyTraitClause<'tcx>, ) -> bool { - let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); + let self_ty = self.deeply_resolve_ignoring_regions(trait_pred.self_ty()); self.enter_forall(self_ty, |ty: Ty<'_>| { let Some(generics) = self.tcx.hir_get_generics(obligation.cause.body_def_id) else { return false; @@ -2498,7 +2499,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Do not suggest removal of borrow from type arguments. return; } - let trait_pred = self.resolve_vars_if_possible(trait_pred); + let trait_pred = self.deeply_resolve_ignoring_regions(trait_pred); if trait_pred.has_non_region_infer() { // Do not ICE while trying to find if a reborrow would succeed on a trait with // unresolved bindings. @@ -2604,7 +2605,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Only suggest this if the expression behind the semicolon implements the predicate && let Some(typeck_results) = &self.typeck_results && let Some(ty) = - typeck_results.expr_ty_opt(expr).map(|ty| self.resolve_vars_if_possible(ty)) + typeck_results.expr_ty_opt(expr).map(|ty| self.deeply_resolve_ignoring_regions(ty)) && self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty( obligation.param_env, trait_pred.map_bound(|trait_pred| (trait_pred, ty)) )) @@ -2716,7 +2717,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { hir::ExprKind::Closure(closure) => closure.def_id, _ => match typeck_results .expr_ty_adjusted_opt(arg) - .map(|ty| *self.resolve_vars_if_possible(ty).peel_refs().kind()) + .map(|ty| *self.deeply_resolve_ignoring_regions(ty).peel_refs().kind()) { Some(ty::Closure(def_id, _)) => def_id.as_local()?, _ => return None, @@ -3795,10 +3796,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } let capture_ty = - self.tcx.erase_and_anonymize_regions(self.resolve_vars_if_possible(capture_ty)); + self.tcx.erase_and_anonymize_regions(self.deeply_resolve_ignoring_regions(capture_ty)); let Some(capture) = captures.iter().zip(upvar_tys).find_map(|(&capture, upvar_ty)| { - let upvar_ty = - self.tcx.erase_and_anonymize_regions(self.resolve_vars_if_possible(upvar_ty)); + let upvar_ty = self + .tcx + .erase_and_anonymize_regions(self.deeply_resolve_ignoring_regions(upvar_ty)); (upvar_ty == capture_ty).then_some(capture) }) else { return false; @@ -4133,10 +4135,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } ObligationCauseCode::Coercion { source, target } => { - let source = - tcx.short_string(self.resolve_vars_if_possible(source), err.long_ty_path()); - let target = - tcx.short_string(self.resolve_vars_if_possible(target), err.long_ty_path()); + let source = tcx + .short_string(self.deeply_resolve_ignoring_regions(source), err.long_ty_path()); + let target = tcx + .short_string(self.deeply_resolve_ignoring_regions(target), err.long_ty_path()); err.note(with_forced_trimmed_paths!(format!( "required for the cast from `{source}` to `{target}`", ))); @@ -4408,7 +4410,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.note("shared static variables must have a type that implements `Sync`"); } ObligationCauseCode::BuiltinDerived(ref data) => { - let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); + let parent_trait_ref = self.deeply_resolve_ignoring_regions(data.parent_trait_pred); let ty = parent_trait_ref.skip_binder().self_ty(); if parent_trait_ref.references_error() { // NOTE(eddyb) this was `.cancel()`, but `err` @@ -4422,7 +4424,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let is_upvar_tys_infer_tuple = if !matches!(ty.kind(), ty::Tuple(..)) { false } else if let ObligationCauseCode::BuiltinDerived(data) = &*data.parent_code { - let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); + let parent_trait_ref = + self.deeply_resolve_ignoring_regions(data.parent_trait_pred); let nested_ty = parent_trait_ref.skip_binder().self_ty(); matches!(nested_ty.kind(), ty::Coroutine(..)) || matches!(nested_ty.kind(), ty::Closure(..)) @@ -4559,7 +4562,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } ObligationCauseCode::ImplDerived(ref data) => { let mut parent_trait_pred = - self.resolve_vars_if_possible(data.derived.parent_trait_pred); + self.deeply_resolve_ignoring_regions(data.derived.parent_trait_pred); let parent_def_id = parent_trait_pred.def_id(); if tcx.is_diagnostic_item(sym::FromResidual, parent_def_id) && !tcx.features().enabled(sym::try_trait_v2) @@ -4571,7 +4574,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } if tcx.is_diagnostic_item(sym::PinDerefMutHelper, parent_def_id) { let parent_predicate = - self.resolve_vars_if_possible(data.derived.parent_trait_pred); + self.deeply_resolve_ignoring_regions(data.derived.parent_trait_pred); // Skip PinDerefMutHelper in suggestions, but still show downstream suggestions. @@ -4697,7 +4700,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // the type `X`", like we would otherwise do in test `supertrait-auto-trait.rs`. while let ObligationCauseCode::BuiltinDerived(derived) = &*data.parent_code { let child_trait_ref = - self.resolve_vars_if_possible(derived.parent_trait_pred); + self.deeply_resolve_ignoring_regions(derived.parent_trait_pred); let child_def_id = child_trait_ref.def_id(); if seen_requirements.insert(child_def_id) { break; @@ -4710,7 +4713,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { while let ObligationCauseCode::ImplDerived(child) = &*data.parent_code { // Skip redundant recursive obligation notes. See `ui/issue-20413.rs`. let child_trait_pred = - self.resolve_vars_if_possible(child.derived.parent_trait_pred); + self.deeply_resolve_ignoring_regions(child.derived.parent_trait_pred); let child_def_id = child_trait_pred.def_id(); if seen_requirements.insert(child_def_id) { break; @@ -4750,7 +4753,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } ObligationCauseCode::ImplDerivedHost(ref data) => { let self_ty = tcx.short_string( - self.resolve_vars_if_possible(data.derived.parent_host_clause.self_ty()), + self.deeply_resolve_ignoring_regions(data.derived.parent_host_clause.self_ty()), err.long_ty_path(), ); let trait_path = tcx.short_string( @@ -4804,7 +4807,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } ObligationCauseCode::WellFormedDerived(ref data) => { - let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); + let parent_trait_ref = self.deeply_resolve_ignoring_regions(data.parent_trait_pred); let parent_predicate = parent_trait_ref; *closure_capture_ty = Some(parent_trait_ref.skip_binder().self_ty()); @@ -4979,7 +4982,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) { let future_trait = self.tcx.require_lang_item(LangItem::Future, span); - let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); + let self_ty = self.deeply_resolve_ignoring_regions(trait_pred.self_ty()); let impls_future = self.type_implements_trait( future_trait, [self.tcx.instantiate_bound_regions_with_erased(self_ty)], @@ -5005,7 +5008,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .normalize(Unnormalized::new_wip(projection_ty)); debug!( - normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty) + normalized_projection_type = ?self.deeply_resolve_ignoring_regions(projection_ty) ); let try_obligation = self.mk_trait_obligation_with_new_self_ty( obligation.param_env, @@ -5646,7 +5649,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut print_root_expr = true; let mut assocs = vec![]; let mut expr = expr; - let mut prev_ty = self.resolve_vars_if_possible( + let mut prev_ty = self.deeply_resolve_ignoring_regions( typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)), ); while let hir::ExprKind::MethodCall(path_segment, rcvr_expr, args, span) = expr.kind { @@ -5656,7 +5659,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { expr = rcvr_expr; let assocs_in_this_method = self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env); - prev_ty = self.resolve_vars_if_possible( + prev_ty = self.deeply_resolve_ignoring_regions( typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)), ); self.look_for_iterator_item_mistakes( @@ -5685,7 +5688,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } if let hir::Node::Param(param) = parent { // ...and it is an fn argument. - let prev_ty = self.resolve_vars_if_possible( + let prev_ty = self.deeply_resolve_ignoring_regions( typeck_results .node_type_opt(param.hir_id) .unwrap_or(Ty::new_misc_error(tcx)), @@ -5850,7 +5853,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { projection, )); if ocx.try_evaluate_obligations().no_errors() - && let ty = self.resolve_vars_if_possible(ty) + && let ty = self.deeply_resolve_ignoring_regions(ty) && !ty.is_ty_var() { assocs_in_this_method.push(Some((span, (def_id, ty)))); @@ -5939,7 +5942,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Resolve what each bound associated type actually is for the returned expression, // and keep only the ones that diverged from the signature. - let expr_ty = self.resolve_vars_if_possible( + let expr_ty = self.deeply_resolve_ignoring_regions( typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)), ); let assocs = self.probe_assoc_types_at_expr( @@ -6098,7 +6101,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let hir::ExprKind::MethodCall(segment, rcvr, args, ..) = call.kind else { return }; let Some(typeck) = &self.typeck_results else { return }; let Some(rcvr_ty) = typeck.expr_ty_adjusted_opt(rcvr) else { return }; - let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty); + let rcvr_ty = self.deeply_resolve_ignoring_regions(rcvr_ty); let autoderef = (self.autoderef_steps)(rcvr_ty); for (ty, def_id) in autoderef.iter().filter_map(|(ty, obligations)| { if let ty::Adt(def, _) = ty.kind() diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index f0fb44523d651..802393a22b7e5 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -31,13 +31,13 @@ impl<'tcx> InferCtxt<'tcx> { } fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { - let ty = self.resolve_vars_if_possible(ty); + let ty = self.deeply_resolve_ignoring_regions(ty); let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, DUMMY_SP); traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id) } fn type_is_clone_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { - let ty = self.resolve_vars_if_possible(ty); + let ty = self.deeply_resolve_ignoring_regions(ty); let clone_def_id = self.tcx.require_lang_item(LangItem::Clone, DUMMY_SP); traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, clone_def_id) } @@ -47,7 +47,7 @@ impl<'tcx> InferCtxt<'tcx> { param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, ) -> bool { - let ty = self.resolve_vars_if_possible(ty); + let ty = self.deeply_resolve_ignoring_regions(ty); let use_cloned_def_id = self.tcx.require_lang_item(LangItem::UseCloned, DUMMY_SP); traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, use_cloned_def_id) } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 60339b1982233..336500ecdcd85 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -176,7 +176,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< } else if trait_pred.polarity() == ty::ClausePolarity::Positive { match self.0.tcx.as_lang_item(trait_pred.def_id()) { Some(LangItem::Sized) | Some(LangItem::MetaSized) => { - let predicate = self.resolve_vars_if_possible(goal.predicate); + let predicate = self.deeply_resolve_ignoring_regions(goal.predicate); if sizedness_fast_path(self.tcx, predicate, goal.param_env) { Outcome::TriviallyHolds } else { @@ -184,8 +184,9 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< } } Some(LangItem::Copy | LangItem::Clone) => { - let self_ty = - self.resolve_vars_if_possible(trait_pred.self_ty().skip_binder()); + let self_ty = self.deeply_resolve_ignoring_regions( + trait_pred.self_ty().skip_binder(), + ); // Unlike `Sized` traits, which always prefer the built-in impl, // `Copy`/`Clone` may be shadowed by a param-env candidate which // could force a lifetime error or guide inference. While that's @@ -227,7 +228,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< return Outcome::NoFastPath; } - let ty = self.resolve_vars_if_possible(outlives.0); + let ty = self.deeply_resolve_ignoring_regions(outlives.0); let mut infer_collector = CollectNonRegionInfer { infers: Default::default(), visited: Default::default(), @@ -464,7 +465,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< | TypingMode::Reflection | TypingMode::PostBorrowck { .. } => false, TypingMode::PostAnalysis | TypingMode::Codegen => { - let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref); + let poly_trait_ref = self.deeply_resolve_ignoring_regions(goal_trait_ref); !poly_trait_ref.still_further_specializable() } TypingMode::ErasedNotCoherence(MayBeErased) => { @@ -519,7 +520,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< fn emit_next_solver_overflow_fcw(&self, goal: Goal<'tcx, ty::Predicate<'tcx>>, span: Span) { let tcx = self.tcx; - let goal = self.resolve_vars_if_possible(goal); + let goal = self.deeply_resolve_ignoring_regions(goal); let mut visitor = OverflowedGoalChain { span, predicates: vec![], diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 1c7d5b742e1ac..de37087ac09ef 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -141,7 +141,7 @@ pub(super) fn try_ambiguity_error_for_stalled<'tcx>( root_obligation.cause.span, format!( "did not expect successful goal when collecting ambiguity errors for `{:?}`", - infcx.resolve_vars_if_possible(root_obligation.predicate), + infcx.deeply_resolve_ignoring_regions(root_obligation.predicate), ), ); None @@ -150,7 +150,7 @@ pub(super) fn try_ambiguity_error_for_stalled<'tcx>( span_bug!( root_obligation.cause.span, "did not expect selection error when collecting ambiguity errors for `{:?}`", - infcx.resolve_vars_if_possible(root_obligation.predicate), + infcx.deeply_resolve_ignoring_regions(root_obligation.predicate), ) } } @@ -178,7 +178,7 @@ fn find_best_leaf_obligation<'tcx>( obligation: &PredicateObligation<'tcx>, consider_ambiguities: bool, ) -> PredicateObligation<'tcx> { - let obligation = infcx.resolve_vars_if_possible(obligation.clone()); + let obligation = infcx.deeply_resolve_ignoring_regions(obligation.clone()); // FIXME: we use a probe here as the `BestObligation` visitor does not // check whether it uses candidates which get shadowed by where-bounds. // diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index aaba2f86da598..829068461d295 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -14,7 +14,7 @@ use std::assert_matches; use rustc_infer::infer::InferCtxt; use rustc_macros::extension; use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult}; -use rustc_middle::ty::{RequiredDepth, TyCtxt, VisitorResult, eager_resolve_vars, try_visit}; +use rustc_middle::ty::{RequiredDepth, TyCtxt, VisitorResult, deeply_resolve_via_unification_table, try_visit}; use rustc_middle::{bug, ty}; use rustc_next_trait_solver::canonical::instantiate_canonical_state; use rustc_next_trait_solver::solve::{MaybeCause, MaybeInfo, SolverDelegateEvalExt as _, inspect}; @@ -170,7 +170,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { self.final_state, ); - return eager_resolve_vars(&**infcx, impl_args); + return deeply_resolve_via_unification_table(&**infcx, impl_args); } inspect::ProbeStep::AddGoal(..) => {} inspect::ProbeStep::MakeCanonicalResponse { .. } @@ -361,7 +361,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { depth, orig_values, prev_universe, - goal: eager_resolve_vars(&**infcx, uncanonicalized_goal), + goal: deeply_resolve_via_unification_table(&**infcx, uncanonicalized_goal), result, final_revision, source, diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index bff35154ed10d..9430b6c4b3307 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -42,7 +42,7 @@ where { let infcx = at.infcx; let value = value.skip_normalization(); - let value = infcx.resolve_vars_if_possible(value); + let value = infcx.deeply_resolve_ignoring_regions(value); if !infcx.tcx.renormalize_rigid_aliases() && !value.has_non_rigid_aliases() { return Normalized { value, obligations: Default::default() }; @@ -59,7 +59,7 @@ where Ok(result) => result, Err(err) => return Err(err), }; - let normalized = infcx.resolve_vars_if_possible(infer_term); + let normalized = infcx.deeply_resolve_ignoring_regions(infer_term); let normalization_was_ambiguous = match result.certainty { Certainty::Yes => NormalizationWasAmbiguous::No, Certainty::Maybe { .. } => { diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 8667eb3af3da7..fadc64ed4af5c 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -334,9 +334,9 @@ impl<'tcx> AutoTraitFinder<'tcx> { continue; } - // Call `infcx.resolve_vars_if_possible` to see if we can + // Call `infcx.deeply_resolve_ignoring_regions` to see if we can // get rid of any inference variables. - let obligation = infcx.resolve_vars_if_possible(Obligation::new( + let obligation = infcx.deeply_resolve_ignoring_regions(Obligation::new( tcx, dummy_cause.clone(), new_env, @@ -658,7 +658,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { fresh_preds.insert(self.clean_pred(selcx.infcx, obligation.predicate)); // Resolve any inference variables that we can, to help selection succeed - let predicate = selcx.infcx.resolve_vars_if_possible(obligation.predicate); + let predicate = selcx.infcx.deeply_resolve_ignoring_regions(obligation.predicate); // We only add a predicate as a user-displayable bound if // it involves a generic parameter, and doesn't contain diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 24217aaf75fe7..34102501613ca 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -333,7 +333,7 @@ fn overlap<'tcx>( .iter() .any(|c| c.0.involves_placeholders()); - let mut impl_header = infcx.resolve_vars_if_possible(impl1_header); + let mut impl_header = infcx.deeply_resolve_ignoring_regions(impl1_header); // Deeply normalize the impl header for diagnostics, ignoring any errors if this fails. if infcx.next_trait_solver() { @@ -451,7 +451,7 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>( .filter(|error| { matches!(error.code, FulfillmentErrorCode::Ambiguity { overflow: Some(true) }) }) - .map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate)) + .map(|e| infcx.deeply_resolve_ignoring_regions(e.obligation.predicate)) .collect(), } } else { @@ -540,8 +540,9 @@ fn impl_intersection_has_negative_obligation( // Right above we plug inference variables with placeholders, // this gets us new impl1_header_args with the inference variables actually resolved // to those placeholders. - let impl1_header_args = infcx.resolve_vars_if_possible(impl1_header.impl_args); - // So there are no infer variables left now, except regions which aren't resolved by `resolve_vars_if_possible`. + let impl1_header_args = infcx.deeply_resolve_ignoring_regions(impl1_header.impl_args); + // So there are no infer variables left now, except regions which aren't resolved by + // `deeply_resolve_ignoring_regions`. assert!(!impl1_header_args.has_non_region_infer()); let param_env = ty::EarlyBinder::bind(tcx, tcx.param_env(impl1_def_id)) diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index 127a46f60b3d9..631d404d93845 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -33,7 +33,7 @@ pub fn evaluate_host_effect_obligation<'tcx>( ); } - let ref obligation = selcx.infcx.resolve_vars_if_possible(obligation.clone()); + let ref obligation = selcx.infcx.deeply_resolve_ignoring_regions(obligation.clone()); // Force ambiguity for infer self ty. if obligation.predicate.self_ty().is_ty_var() { diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index ddbb56affcff1..c51c5feafb4a2 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -145,7 +145,7 @@ where // this helps to reduce duplicate errors, as well as making // debug output much nicer to read and so on. debug_assert!(!obligation.param_env.has_non_region_infer()); - obligation.predicate = infcx.resolve_vars_if_possible(obligation.predicate); + obligation.predicate = infcx.deeply_resolve_ignoring_regions(obligation.predicate); debug!(?obligation, "register_predicate_obligation"); @@ -236,7 +236,7 @@ where } self.infcx - .resolve_vars_if_possible(pending_obligation.obligation.predicate) + .deeply_resolve_ignoring_regions(pending_obligation.obligation.predicate) .visit_with(&mut StalledOnCoroutines { stalled_coroutines: self.stalled_coroutines, cache: Default::default(), @@ -387,7 +387,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { debug!(?obligation, "pre-resolve"); if obligation.predicate.has_non_region_infer() { - obligation.predicate = self.selcx.infcx.resolve_vars_if_possible(obligation.predicate); + obligation.predicate = + self.selcx.infcx.deeply_resolve_ignoring_regions(obligation.predicate); } let obligation = &pending_obligation.obligation; @@ -903,7 +904,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { debug!( "process_predicate: pending obligation {:?} now stalled on {:?}", - infcx.resolve_vars_if_possible(obligation.clone()), + infcx.deeply_resolve_ignoring_regions(obligation.clone()), stalled_on ); @@ -954,13 +955,15 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { } ProjectAndUnifyResult::Holds(os) => { let input_projection_term = infcx - .resolve_vars_if_possible(project_obligation.predicate) + .deeply_resolve_ignoring_regions(project_obligation.predicate) .map_bound(|p| p.projection_term); let all_same_projection_term = os.iter().all(|o| { let Some(proj_clause) = o.predicate.as_projection_clause() else { return false; }; - infcx.resolve_vars_if_possible(proj_clause).map_bound(|p| p.projection_term) + infcx + .deeply_resolve_ignoring_regions(proj_clause) + .map_bound(|p| p.projection_term) == input_projection_term }); if all_same_projection_term { @@ -1029,7 +1032,7 @@ fn args_infer_vars<'tcx>( ) -> impl Iterator { selcx .infcx - .resolve_vars_if_possible(args) + .deeply_resolve_ignoring_regions(args) .skip_binder() // ok because this check doesn't care about regions .iter() .filter(|arg| arg.has_non_region_infer()) diff --git a/compiler/rustc_trait_selection/src/traits/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/implied_outlives_bounds.rs index c0df53db4ab34..286de7bed0db8 100644 --- a/compiler/rustc_trait_selection/src/traits/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/implied_outlives_bounds.rs @@ -64,7 +64,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( continue; } - let arg = ocx.infcx.resolve_vars_if_possible(arg); + let arg = ocx.infcx.deeply_resolve_ignoring_regions(arg); // From the full set of obligations, just filter down to the region relationships. for obligation in wf::unnormalized_obligations(ocx.infcx, param_env, arg, DUMMY_SP, CRATE_DEF_ID) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 7357d1738d8c3..155cb6d6bbb02 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -232,7 +232,8 @@ fn pred_known_to_hold_modulo_regions<'tcx>( // is not smart enough, so we fall back to fulfillment when we're not certain // that an obligation holds or not. Even still, we must make sure that // the we do no inference in the process of checking this obligation. - let goal = infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env)); + let goal = + infcx.deeply_resolve_ignoring_regions((obligation.predicate, obligation.param_env)); infcx.probe(|_| { let ocx = ObligationCtxt::new(infcx); ocx.register_obligation(obligation); @@ -240,7 +241,7 @@ fn pred_known_to_hold_modulo_regions<'tcx>( let errors = ocx.evaluate_obligations_error_on_ambiguity(); match errors { // Only known to hold if we did no inference. - TraitErrors::NoErrors => infcx.resolve_vars_if_possible(goal) == goal, + TraitErrors::NoErrors => infcx.deeply_resolve_ignoring_regions(goal) == goal, TraitErrors::HasErrors(errors) => { debug!(?errors); @@ -631,7 +632,7 @@ pub fn try_evaluate_const<'tcx, E: Debug>( normalize_ty: impl FnOnce(Unnormalized<'tcx, Ty<'tcx>>) -> Result, E>, ) -> Result, EvaluateConstErr> { let tcx = infcx.tcx; - let ct = infcx.resolve_vars_if_possible(ct); + let ct = infcx.deeply_resolve_ignoring_regions(ct); debug!(?ct); match ct.kind() { diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 2d2c4ff38acee..d52dd8c98d91d 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -78,7 +78,7 @@ impl<'tcx> At<'_, 'tcx> { .normalize(value) .into_value_registering_obligations(self.infcx, &mut *fulfill_cx); let errors = fulfill_cx.evaluate_obligations_error_on_ambiguity(self.infcx); - let value = self.infcx.resolve_vars_if_possible(value); + let value = self.infcx.deeply_resolve_ignoring_regions(value); match errors { TraitErrors::NoErrors => Ok(value), TraitErrors::HasErrors(errors) => { @@ -171,7 +171,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { } fn fold>>(&mut self, value: T) -> T { - let value = self.selcx.infcx.resolve_vars_if_possible(value); + let value = self.selcx.infcx.deeply_resolve_ignoring_regions(value); debug!(?value); assert!( diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index bcb932f74b1f8..ac7a0586a827a 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -1,6 +1,6 @@ use rustc_infer::infer::InferOk; use rustc_infer::infer::canonical::QueryRegionConstraint; -use rustc_infer::infer::resolve::OpportunisticRegionResolver; +use rustc_infer::infer::resolve::DeepRegionResolver; use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds; use rustc_macros::extension; use rustc_middle::infer::canonical::{OriginalQueryValues, QueryRegionConstraints}; @@ -39,8 +39,8 @@ fn implied_outlives_bounds<'a, 'tcx>( ty: Ty<'tcx>, disable_implied_bounds_hack: bool, ) -> Vec> { - let ty = infcx.resolve_vars_if_possible(ty); - let ty = OpportunisticRegionResolver::new(infcx).fold_ty(ty); + let ty = infcx.deeply_resolve_ignoring_regions(ty); + let ty = DeepRegionResolver::new(infcx).fold_ty(ty); // We do not expect existential variables in implied bounds. // We may however encounter unconstrained lifetime variables diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index f3504e96965e8..496ddbfebd4f0 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -7,7 +7,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::def_id::DefId; use rustc_infer::infer::DefineOpaqueTypes; -use rustc_infer::infer::resolve::OpportunisticRegionResolver; +use rustc_infer::infer::resolve::DeepRegionResolver; use rustc_infer::traits::{ObligationCauseCode, PredicateObligations}; use rustc_middle::traits::select::OverflowError; use rustc_middle::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedData}; @@ -309,7 +309,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( ) -> Result>, InProgress> { let infcx = selcx.infcx; debug_assert!(!selcx.infcx.next_trait_solver()); - let projection_term = infcx.resolve_vars_if_possible(projection_term); + let projection_term = infcx.deeply_resolve_ignoring_regions(projection_term); let cache_key = ProjectionCacheKey::new(projection_term, param_env); // FIXME(#20304) For now, I am caching here, which is good, but it @@ -388,7 +388,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( // an impl, where-clause etc) and hence we must // re-normalize it - let projected_term = selcx.infcx.resolve_vars_if_possible(projected_term); + let projected_term = selcx.infcx.deeply_resolve_ignoring_regions(projected_term); let mut result = if projected_term.has_aliases() { let normalized_ty = normalize_with_depth_to( @@ -584,7 +584,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( const_of_item_or_delayed_bug(tcx, def_id).instantiate(tcx, args).map(Into::into) }; - let term = selcx.infcx.resolve_vars_if_possible(term); + let term = selcx.infcx.deeply_resolve_ignoring_regions(term); let term = normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, term, obligations); @@ -1053,7 +1053,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // NOTE(eddyb) inference variables can resolve to parameters, so // assume `poly_trait_ref` isn't monomorphic, if it contains any. let poly_trait_ref = - selcx.infcx.resolve_vars_if_possible(trait_ref); + selcx.infcx.deeply_resolve_ignoring_regions(trait_ref); !poly_trait_ref.still_further_specializable() } } @@ -1326,7 +1326,7 @@ fn confirm_candidate<'cx, 'tcx>( if let Ok(Projected::Progress(progress)) = &mut result && progress.term.has_infer_regions() { - progress.term = progress.term.fold_with(&mut OpportunisticRegionResolver::new(selcx.infcx)); + progress.term = progress.term.fold_with(&mut DeepRegionResolver::new(selcx.infcx)); } result @@ -2221,7 +2221,7 @@ impl<'cx, 'tcx> ProjectionCacheKeyExt<'cx, 'tcx> for ProjectionCacheKey<'tcx> { // from a specific call to `opt_normalize_projection_type` - if // there's no precise match, the original cache entry is "stranded" // anyway. - infcx.resolve_vars_if_possible(predicate.projection_term), + infcx.deeply_resolve_ignoring_regions(predicate.projection_term), obligation.param_env, ) }) diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 39f439cad64d3..79e1b3f2c9c4d 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -145,7 +145,7 @@ where })?; // Next trait solver performs operations locally, and normalize goals should resolve vars. - let value = infcx.resolve_vars_if_possible(value); + let value = infcx.deeply_resolve_ignoring_regions(value); let region_obligations = infcx.take_registered_region_obligations(); let region_assumptions = infcx.take_registered_region_assumptions(); diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 30700689a8ff0..bd61bcc7f4d07 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -38,7 +38,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env: obligation.param_env, cause: obligation.cause.clone(), recursion_depth: obligation.recursion_depth, - predicate: self.infcx.resolve_vars_if_possible(obligation.predicate), + predicate: self.infcx.deeply_resolve_ignoring_regions(obligation.predicate), }; if obligation.predicate.skip_binder().self_ty().is_ty_var() { @@ -209,7 +209,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } self.infcx.probe(|_| { - let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); + let poly_trait_predicate = + self.infcx.deeply_resolve_ignoring_regions(obligation.predicate); let placeholder_trait_predicate = self.infcx.enter_forall_and_leak_universe(poly_trait_predicate); @@ -927,7 +928,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } self.infcx.probe(|_snapshot| { - let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); + let poly_trait_predicate = + self.infcx.deeply_resolve_ignoring_regions(obligation.predicate); self.infcx.enter_forall(poly_trait_predicate, |placeholder_trait_predicate| { let self_ty = placeholder_trait_predicate.self_ty(); let principal_trait_ref = match self_ty.kind() { @@ -1373,7 +1375,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PolyTraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { - let self_ty = self.infcx.resolve_vars_if_possible(obligation.self_ty()); + let self_ty = self.infcx.deeply_resolve_ignoring_regions(obligation.self_ty()); match self_ty.skip_binder().kind() { ty::FnPtr(..) => candidates.vec.push(BuiltinCandidate), diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 15dfd58d6b753..a9ac96424d018 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -379,7 +379,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } if !candidate_set.ambiguous && no_candidates_apply { - let trait_ref = self.infcx.resolve_vars_if_possible( + let trait_ref = self.infcx.deeply_resolve_ignoring_regions( stack.obligation.predicate.skip_binder().trait_ref, ); if !trait_ref.references_error() { @@ -508,15 +508,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result { debug_assert!(!self.infcx.next_trait_solver()); self.evaluation_probe(|this| { - let goal = - this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env)); + let goal = this + .infcx + .deeply_resolve_ignoring_regions((obligation.predicate, obligation.param_env)); let mut result = this.evaluate_predicate_recursively( TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), obligation.clone(), )?; // If the predicate has done any inference, then downgrade the // result to ambiguous. - if this.infcx.resolve_vars_if_possible(goal) != goal { + if this.infcx.deeply_resolve_ignoring_regions(goal) != goal { result = result.max(EvaluatedToAmbig); } Ok(result) @@ -1445,7 +1446,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("is_knowable()"); - let predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); + let predicate = self.infcx.deeply_resolve_ignoring_regions(obligation.predicate); // Okay to skip binder because of the nature of the // trait-ref-is-knowable check, which does not care about @@ -2470,7 +2471,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { match self.match_impl(impl_def_id, impl_trait_header, obligation) { Ok(args) => args, Err(()) => { - let predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); + let predicate = self.infcx.deeply_resolve_ignoring_regions(obligation.predicate); bug!("impl {impl_def_id:?} was matchable against {predicate:?} but now is not") } } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index f7351a6b8ed36..9a0894891f625 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -215,7 +215,7 @@ fn fulfill_implication<'tcx>( // Now resolve the *generic parameters* we built for the target earlier, replacing // the inference variables inside with whatever we got from fulfillment. - Ok(infcx.resolve_vars_if_possible(target_args)) + Ok(infcx.deeply_resolve_ignoring_regions(target_args)) } pub(super) fn specialization_enabled_in(tcx: TyCtxt<'_>, _: LocalCrate) -> bool { diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index e5fff1eb0fd04..2313ceaabd1ca 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -69,7 +69,7 @@ impl<'tcx> At<'_, 'tcx> { return Err(errors); } - Ok(self.infcx.resolve_vars_if_possible(new_infer)) + Ok(self.infcx.deeply_resolve_ignoring_regions(new_infer)) } else { Ok(self.normalize(term).into_value_registering_obligations(self.infcx, fulfill_cx)) } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 632e805388eb6..9045d9a644ac0 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -98,7 +98,7 @@ pub fn unnormalized_obligations<'tcx>( span: Span, body_def_id: LocalDefId, ) -> Option> { - debug_assert_eq!(term, infcx.resolve_vars_if_possible(term)); + debug_assert_eq!(term, infcx.deeply_resolve_ignoring_regions(term)); // However, if `term` IS an unresolved inference variable, returns `None`, // because we are not able to make any progress at all. This is to prevent diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index e03b67f8e4d39..006e793b7a5eb 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -72,7 +72,7 @@ pub(crate) fn codegen_select_candidate<'tcx>( return Err(CodegenObligationError::Unimplemented); } - let impl_source = infcx.resolve_vars_if_possible(impl_source); + let impl_source = infcx.deeply_resolve_ignoring_regions(impl_source); let impl_source = tcx.erase_and_anonymize_regions(impl_source); if impl_source.has_non_region_infer() { // Unused generic types or consts on an impl get replaced with inference vars, diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs index b7ff4cca0bb1f..6deb6c8e93bb2 100644 --- a/compiler/rustc_traits/src/coroutine_witnesses.rs +++ b/compiler/rustc_traits/src/coroutine_witnesses.rs @@ -1,7 +1,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::canonical::QueryRegionConstraint; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; -use rustc_infer::infer::resolve::OpportunisticRegionResolver; +use rustc_infer::infer::resolve::DeepRegionResolver; use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions}; use rustc_span::def_id::DefId; @@ -90,7 +90,7 @@ fn compute_assumptions<'tcx>( Default::default(), ) .constraints - .fold_with(&mut OpportunisticRegionResolver::new(&infcx)); + .fold_with(&mut DeepRegionResolver::new(&infcx)); tcx.mk_outlives_from_iter( constraints diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 1ba385e86b310..5ee83ae651713 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -36,7 +36,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable> + Par None, ); - let resolved_value = infcx.resolve_vars_if_possible(normalized_value); + let resolved_value = infcx.deeply_resolve_ignoring_regions(normalized_value); // It's unclear when `resolve_vars` would have an effect in a // fresh `InferCtxt`. If this assert does trigger, it will give // us a test case. diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 8d1d3372fac69..88746f374b441 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -514,7 +514,7 @@ pub trait InferCtxtLike: Sized { ty: ::Const, ) -> ::Const; - fn resolve_vars_if_possible(&self, value: T) -> T + fn deeply_resolve_ignoring_regions(&self, value: T) -> T where T: TypeFoldable; @@ -628,20 +628,27 @@ where } } -/// Resolves ty, region, and const vars to their inferred values or their root vars. -pub fn eager_resolve_vars>( +/// Where possible, replaces type/const/region variables in `value` with their final value. +/// If a type/const/region variable has not (yet) been unified, it is left as is. +/// +/// This is an idempotent operation that does not affect inference state in any way, +/// which means it's safe to call this function at will. +pub fn deeply_resolve_via_unification_table< + Infcx: InferCtxtLike, + T: TypeFoldable, +>( infcx: &Infcx, value: T, ) -> T { if value.has_infer() { - let mut folder = EagerResolver::new(infcx); + let mut folder = DeepVariableResolver::new(infcx); value.fold_with(&mut folder) } else { value } } -struct EagerResolver<'a, D, I = ::Interner> +struct DeepVariableResolver<'a, D, I = ::Interner> where D: InferCtxtLike, I: Interner, @@ -652,13 +659,15 @@ where cache: DelayedMap, } -impl<'a, Infcx: InferCtxtLike> EagerResolver<'a, Infcx> { +impl<'a, Infcx: InferCtxtLike> DeepVariableResolver<'a, Infcx> { fn new(delegate: &'a Infcx) -> Self { - EagerResolver { delegate, cache: Default::default() } + DeepVariableResolver { delegate, cache: Default::default() } } } -impl, I: Interner> TypeFolder for EagerResolver<'_, Infcx> { +impl, I: Interner> TypeFolder + for DeepVariableResolver<'_, Infcx> +{ fn cx(&self) -> I { self.delegate.cx() } diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs index 29193f40959d3..7b747141889fe 100644 --- a/compiler/rustc_type_ir/src/relate/combine.rs +++ b/compiler/rustc_type_ir/src/relate/combine.rs @@ -243,7 +243,7 @@ where ty::Bivariant => { let has_non_region_infer = |arg: I::GenericArg| { arg.has_non_region_infer() - && infcx.resolve_vars_if_possible(arg).has_non_region_infer() + && infcx.deeply_resolve_ignoring_regions(arg).has_non_region_infer() }; if has_non_region_infer(a) || has_non_region_infer(b) { has_unconstrained_bivariant_arg = true; diff --git a/compiler/rustc_type_ir/src/universe.rs b/compiler/rustc_type_ir/src/universe.rs index a5a4b2c02be89..70d192fa074e5 100644 --- a/compiler/rustc_type_ir/src/universe.rs +++ b/compiler/rustc_type_ir/src/universe.rs @@ -57,7 +57,7 @@ fn max_universe_inner< let mut visitor = MaxUniverse::<_, _, VISIT_PLACEHOLDER, VISIT_INFER>::new(infcx); // FIXME: make this a debug_assert and let callers resolve vars. Then the input only needs to // be `TypeVisitable`. - let t = infcx.resolve_vars_if_possible(t); + let t = infcx.deeply_resolve_ignoring_regions(t); t.visit_with(&mut visitor); visitor.max_universe() } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2b1a37cbcda30..7f6392fce691a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1990,7 +1990,7 @@ fn normalize<'tcx>( let normalized = infcx .at(&ObligationCause::dummy(), cx.param_env) .query_normalize(ty) - .map(|resolved| infcx.resolve_vars_if_possible(resolved.value)); + .map(|resolved| infcx.deeply_resolve_ignoring_regions(resolved.value)); match normalized { Ok(normalized_value) => { debug!("normalized {ty:?} to {normalized_value:?}"); diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 13fc6e3bc1bb8..2c42c165243a3 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -432,7 +432,7 @@ fn generate_item_def_id_path( let ty = infcx .at(&ObligationCause::dummy(), tcx.param_env(def_id)) .query_normalize(ty::Binder::dummy(ty.instantiate_identity().skip_norm_wip())) - .map(|resolved| infcx.resolve_vars_if_possible(resolved.value).skip_binder()) + .map(|resolved| infcx.deeply_resolve_ignoring_regions(resolved.value).skip_binder()) .unwrap_or(ty.skip_binder()); if let Some(new_def_id) = ty.ty_adt_def().map(|adt| adt.did()) { def_id = new_def_id; From 2499f6fff3affcc7be465ff63354a033648e70b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 11 Aug 2026 13:45:23 +0200 Subject: [PATCH 28/31] rename opportunistic_resolve to shallow_resolve --- .../src/check/compare_impl_item.rs | 4 +-- .../src/infer/canonical/canonicalizer.rs | 8 ++--- compiler/rustc_infer/src/infer/context.rs | 35 +++++++++---------- compiler/rustc_infer/src/infer/mod.rs | 22 ++++++++++-- .../src/infer/region_constraints/mod.rs | 6 ++-- compiler/rustc_infer/src/infer/resolve.rs | 2 +- .../src/canonical/canonicalizer.rs | 14 ++++---- .../src/placeholder.rs | 2 +- .../src/solve/eval_ctxt/mod.rs | 8 ++--- .../src/traits/coherence.rs | 2 +- compiler/rustc_type_ir/src/infer_ctxt.rs | 30 +++++++--------- compiler/rustc_type_ir/src/universe.rs | 6 ++-- 12 files changed, 74 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index e0b9f7dd58bc9..c95638629adde 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1296,7 +1296,7 @@ fn check_region_late_boundedness<'tcx>( .inner .borrow_mut() .unwrap_region_constraints() - .opportunistic_resolve_var(tcx, vid) + .shallow_resolve_region_var(tcx, vid) && let ty::ReLateParam(ty::LateParamRegion { kind: ty::LateParamRegionKind::Named(trait_param_def_id), .. @@ -1321,7 +1321,7 @@ fn check_region_late_boundedness<'tcx>( .inner .borrow_mut() .unwrap_region_constraints() - .opportunistic_resolve_var(tcx, vid) + .shallow_resolve_region_var(tcx, vid) && let ty::ReLateParam(ty::LateParamRegion { kind: ty::LateParamRegionKind::Named(impl_param_def_id), .. diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 9b3deac32222b..4fe57994057cc 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -165,7 +165,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse { .inner .borrow_mut() .unwrap_region_constraints() - .opportunistic_resolve_var(canonicalizer.tcx, vid); + .shallow_resolve_region_var(canonicalizer.tcx, vid); debug!( "canonical: region var found with vid {vid:?}, \ opportunistically resolved to {r:?}", @@ -183,7 +183,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse { .inner .borrow_mut() .unwrap_region_constraints() - .probe_value(vid) + .try_resolve_region_var(vid) .unwrap_err(); canonicalizer.canonical_var_for_region(CanonicalVarKind::Region(universe), r) } @@ -363,7 +363,7 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { } ty::Infer(ty::IntVar(vid)) => { - let nt = self.infcx.unwrap().opportunistic_resolve_int_var(vid); + let nt = self.infcx.unwrap().shallow_resolve_int_var(vid); if nt != t { return self.fold_ty(nt); } else { @@ -371,7 +371,7 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { } } ty::Infer(ty::FloatVar(vid)) => { - let nt = self.infcx.unwrap().opportunistic_resolve_float_var(vid); + let nt = self.infcx.unwrap().shallow_resolve_float_var(vid); if nt != t { return self.fold_ty(nt); } else { diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 8b84be5d1ffae..4d90e60736995 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -82,14 +82,14 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { } } - fn universe_of_lt(&self, lt: ty::RegionVid) -> Option { - match self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) { + fn universe_of_region(&self, lt: ty::RegionVid) -> Option { + match self.inner.borrow_mut().unwrap_region_constraints().try_resolve_region_var(lt) { Err(universe) => Some(universe), Ok(_) => None, } } - fn universe_of_ct(&self, ct: ty::ConstVid) -> Option { + fn universe_of_const(&self, ct: ty::ConstVid) -> Option { match self.try_resolve_const_var(ct) { Err(universe) => Some(universe), Ok(_) => None, @@ -118,30 +118,27 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.root_const_var(var) } - fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> Ty<'tcx> { - match self.try_resolve_ty_var(vid) { - Ok(ty) => ty, - Err(_) => Ty::new_var(self.tcx, self.root_var(vid)), - } + fn shallow_resolve_ty_var(&self, vid: ty::TyVid) -> Ty<'tcx> { + self.shallow_resolve_ty_var(vid) } - fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> { - self.opportunistic_resolve_int_var(vid) + fn shallow_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> { + self.shallow_resolve_int_var(vid) } - fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> { - self.opportunistic_resolve_float_var(vid) + fn shallow_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> { + self.shallow_resolve_float_var(vid) } - fn opportunistic_resolve_ct_var(&self, vid: ty::ConstVid) -> ty::Const<'tcx> { - match self.try_resolve_const_var(vid) { - Ok(ct) => ct, - Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid)), - } + fn shallow_resolve_const_var(&self, vid: ty::ConstVid) -> ty::Const<'tcx> { + self.shallow_resolve_const_var(vid) } - fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> { - self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid) + fn shallow_resolve_region_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> { + self.inner + .borrow_mut() + .unwrap_region_constraints() + .shallow_resolve_region_var(self.tcx, vid) } fn ty_or_const_infer_var_changed(&self, var: TyOrConstInferVar) -> bool { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index b6b733c2c68da..75f7bb7fcd9ec 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1372,9 +1372,27 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().const_unification_table().find(var).vid } + /// Resolves a const var to a rigid const, if it was constrained to one, + /// or else the root const var in the unification table. + pub fn shallow_resolve_const_var(&self, vid: ty::ConstVid) -> ty::Const<'tcx> { + match self.try_resolve_const_var(vid) { + Ok(ct) => ct, + Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid)), + } + } + + /// Resolves a type var to a rigid type, if it was constrained to one, + /// or else the root type var in the unification table. + pub fn shallow_resolve_ty_var(&self, vid: ty::TyVid) -> Ty<'tcx> { + match self.try_resolve_ty_var(vid) { + Ok(ty) => ty, + Err(_) => Ty::new_var(self.tcx, self.root_var(vid)), + } + } + /// Resolves an int var to a rigid int type, if it was constrained to one, /// or else the root int var in the unification table. - pub fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> { + pub fn shallow_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> { let mut inner = self.inner.borrow_mut(); let value = inner.int_unification_table().probe_value(vid); match value { @@ -1388,7 +1406,7 @@ impl<'tcx> InferCtxt<'tcx> { /// Resolves a float var to a rigid int type, if it was constrained to one, /// or else the root float var in the unification table. - pub fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> { + pub fn shallow_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> { let mut inner = self.inner.borrow_mut(); let value = inner.float_unification_table().probe_value(vid); match value { diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 240b288728832..c17933d2629a5 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -672,7 +672,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { /// Resolves a region var to its value in the unification table, if it exists. /// Otherwise, it is resolved to the root `ReVar` in the table. - pub fn opportunistic_resolve_var( + pub fn shallow_resolve_region_var( &mut self, tcx: TyCtxt<'tcx>, vid: ty::RegionVid, @@ -685,7 +685,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } } - pub fn probe_value( + pub fn try_resolve_region_var( &mut self, vid: ty::RegionVid, ) -> Result, ty::UniverseIndex> { @@ -743,7 +743,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { | ty::ReEarlyParam(..) | ty::ReError(_) => ty::UniverseIndex::ROOT, ty::RePlaceholder(placeholder) => placeholder.universe, - ty::ReVar(vid) => match self.probe_value(vid) { + ty::ReVar(vid) => match self.try_resolve_region_var(vid) { Ok(value) => self.universe(value), Err(universe) => universe, }, diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 2b92c9b587bdf..f78e1d5b2d3b2 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -104,7 +104,7 @@ impl<'a, 'tcx> TypeFolder> for DeepRegionResolver<'a, 'tcx> { .inner .borrow_mut() .unwrap_region_constraints() - .opportunistic_resolve_var(TypeFolder::cx(self), vid), + .shallow_resolve_region_var(TypeFolder::cx(self), vid), _ => r, } } diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index 6047966248bb2..f0f0ebaf2b3bb 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -322,7 +322,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { ty::Infer(i) => match i { ty::TyVar(vid) => { debug_assert_eq!( - self.delegate.opportunistic_resolve_ty_var(vid), + self.delegate.shallow_resolve_ty_var(vid), t, "ty vid should have been resolved fully before canonicalization" ); @@ -339,7 +339,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { } ty::IntVar(vid) => { debug_assert_eq!( - self.delegate.opportunistic_resolve_int_var(vid), + self.delegate.shallow_resolve_int_var(vid), t, "ty vid should have been resolved fully before canonicalization" ); @@ -347,7 +347,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { } ty::FloatVar(vid) => { debug_assert_eq!( - self.delegate.opportunistic_resolve_float_var(vid), + self.delegate.shallow_resolve_float_var(vid), t, "ty vid should have been resolved fully before canonicalization" ); @@ -489,7 +489,7 @@ impl, I: Interner> TypeFolder for Canonicaliz ty::ReVar(vid) => { debug_assert_eq!( - self.delegate.opportunistic_resolve_lt_var(vid), + self.delegate.shallow_resolve_region_var(vid), r, "region vid should have been resolved fully before canonicalization" ); @@ -501,7 +501,7 @@ impl, I: Interner> TypeFolder for Canonicaliz )) } CanonicalizeMode::Response { .. } => { - CanonicalVarKind::Region(self.delegate.universe_of_lt(vid).unwrap()) + CanonicalVarKind::Region(self.delegate.universe_of_region(vid).unwrap()) } } } @@ -534,7 +534,7 @@ impl, I: Interner> TypeFolder for Canonicaliz ty::ConstKind::Infer(i) => match i { ty::InferConst::Var(vid) => { debug_assert_eq!( - self.delegate.opportunistic_resolve_ct_var(vid), + self.delegate.shallow_resolve_const_var(vid), c, "const vid should have been resolved fully before canonicalization" ); @@ -544,7 +544,7 @@ impl, I: Interner> TypeFolder for Canonicaliz CanonicalVarKind::Const(ty::UniverseIndex::ROOT) } CanonicalizeMode::Response { .. } => { - CanonicalVarKind::Const(self.delegate.universe_of_ct(vid).unwrap()) + CanonicalVarKind::Const(self.delegate.universe_of_const(vid).unwrap()) } } } diff --git a/compiler/rustc_next_trait_solver/src/placeholder.rs b/compiler/rustc_next_trait_solver/src/placeholder.rs index e24037e2da7cd..84811a101fb11 100644 --- a/compiler/rustc_next_trait_solver/src/placeholder.rs +++ b/compiler/rustc_next_trait_solver/src/placeholder.rs @@ -248,7 +248,7 @@ where fn fold_region(&mut self, r0: Region) -> Region { let r1 = match r0.kind() { - ty::ReVar(vid) => self.infcx.opportunistic_resolve_lt_var(vid), + ty::ReVar(vid) => self.infcx.shallow_resolve_region_var(vid), _ => r0, }; diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 825105bddd380..abb328f11cc56 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1098,7 +1098,7 @@ where } ty::TermKind::Const(ct) => { if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() { - self.delegate.universe_of_ct(vid).unwrap() + self.delegate.universe_of_const(vid).unwrap() } else { return false; } @@ -1165,7 +1165,7 @@ where return ControlFlow::Break(()); } - self.check_nameable(self.delegate.universe_of_ct(vid).unwrap()) + self.check_nameable(self.delegate.universe_of_const(vid).unwrap()) } ty::ConstKind::Placeholder(p) => self.check_nameable(p.universe()), _ => { @@ -1313,7 +1313,7 @@ where pub(super) fn eager_resolve_region(&self, r: Region) -> Region { if let ty::ReVar(vid) = r.kind() { - self.delegate.opportunistic_resolve_lt_var(vid) + self.delegate.shallow_resolve_region_var(vid) } else { r } @@ -1672,7 +1672,7 @@ where && let ty::RegionKind::ReVar(vid) = re.kind() // This is only safe if we call `eager_resolve_vars` beforehand, // which we do. - && self.delegate.universe_of_lt(vid).unwrap() + && self.delegate.universe_of_region(vid).unwrap() .can_name(max_universe(&**self.delegate, sup_re)) { vis.vars.contains(&vid) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 34102501613ca..5605325309275 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -638,7 +638,7 @@ fn plug_infer_with_placeholders<'tcx>( .inner .borrow_mut() .unwrap_region_constraints() - .opportunistic_resolve_var(self.infcx.tcx, vid); + .shallow_resolve_region_var(self.infcx.tcx, vid); if r.is_var() { let Ok(InferOk { value: (), obligations }) = self.infcx.at(&ObligationCause::dummy(), ty::ParamEnv::empty()).eq( diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 88746f374b441..55a88b0632d47 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -423,25 +423,19 @@ pub trait InferCtxtLike: Sized { ); fn universe_of_ty(&self, ty: ty::TyVid) -> Option; - fn universe_of_lt(&self, lt: ty::RegionVid) -> Option; - fn universe_of_ct(&self, ct: ty::ConstVid) -> Option; + fn universe_of_region(&self, lt: ty::RegionVid) -> Option; + fn universe_of_const(&self, ct: ty::ConstVid) -> Option; fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid; fn sub_unification_table_root_var(&self, var: ty::TyVid) -> ty::TyVid; fn is_sub_unification_table_root_var(&self, var: ty::TyVid) -> bool; fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid; - fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> ::Ty; - fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> ::Ty; - fn opportunistic_resolve_float_var( - &self, - vid: ty::FloatVid, - ) -> ::Ty; - fn opportunistic_resolve_ct_var( - &self, - vid: ty::ConstVid, - ) -> ::Const; - fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> Region; + fn shallow_resolve_ty_var(&self, vid: ty::TyVid) -> ::Ty; + fn shallow_resolve_int_var(&self, vid: ty::IntVid) -> ::Ty; + fn shallow_resolve_float_var(&self, vid: ty::FloatVid) -> ::Ty; + fn shallow_resolve_const_var(&self, vid: ty::ConstVid) -> ::Const; + fn shallow_resolve_region_var(&self, vid: ty::RegionVid) -> Region; fn ty_or_const_infer_var_changed(&self, var: TyOrConstInferVar) -> bool; @@ -675,15 +669,15 @@ impl, I: Interner> TypeFolder fn fold_ty(&mut self, t: I::Ty) -> I::Ty { match t.kind() { ty::Infer(ty::TyVar(vid)) => { - let resolved = self.delegate.opportunistic_resolve_ty_var(vid); + let resolved = self.delegate.shallow_resolve_ty_var(vid); if t != resolved && resolved.has_infer() { resolved.fold_with(self) } else { resolved } } - ty::Infer(ty::IntVar(vid)) => self.delegate.opportunistic_resolve_int_var(vid), - ty::Infer(ty::FloatVar(vid)) => self.delegate.opportunistic_resolve_float_var(vid), + ty::Infer(ty::IntVar(vid)) => self.delegate.shallow_resolve_int_var(vid), + ty::Infer(ty::FloatVar(vid)) => self.delegate.shallow_resolve_float_var(vid), _ => { if t.has_infer() { if let Some(&ty) = self.cache.get(&t) { @@ -701,7 +695,7 @@ impl, I: Interner> TypeFolder fn fold_region(&mut self, r: Region) -> Region { match r.kind() { - ty::ReVar(vid) => self.delegate.opportunistic_resolve_lt_var(vid), + ty::ReVar(vid) => self.delegate.shallow_resolve_region_var(vid), _ => r, } } @@ -709,7 +703,7 @@ impl, I: Interner> TypeFolder fn fold_const(&mut self, c: I::Const) -> I::Const { match c.kind() { ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { - let resolved = self.delegate.opportunistic_resolve_ct_var(vid); + let resolved = self.delegate.shallow_resolve_const_var(vid); if c != resolved && resolved.has_infer() { resolved.fold_with(self) } else { diff --git a/compiler/rustc_type_ir/src/universe.rs b/compiler/rustc_type_ir/src/universe.rs index 70d192fa074e5..1f38edd78023d 100644 --- a/compiler/rustc_type_ir/src/universe.rs +++ b/compiler/rustc_type_ir/src/universe.rs @@ -140,7 +140,7 @@ impl< self.max_universe = self.max_universe.max(p.universe) } ConstKind::Infer(rustc_type_ir::InferConst::Var(inf)) if VISIT_INFER => { - let u = self.infcx.universe_of_ct(inf).unwrap(); + let u = self.infcx.universe_of_const(inf).unwrap(); debug!("var {inf:?} in universe {u:?}"); self.max_universe = self.max_universe.max(u); } @@ -154,12 +154,12 @@ impl< self.max_universe = self.max_universe.max(p.universe) } RegionKind::ReVar(var) if VISIT_INFER => { - match self.infcx.opportunistic_resolve_lt_var(var).kind() { + match self.infcx.shallow_resolve_region_var(var).kind() { RegionKind::RePlaceholder(p) if VISIT_PLACEHOLDER => { self.max_universe = self.max_universe.max(p.universe) } RegionKind::ReVar(var) if VISIT_INFER => { - let u = self.infcx.universe_of_lt(var).unwrap(); + let u = self.infcx.universe_of_region(var).unwrap(); debug!("var {var:?} in universe {u:?}"); self.max_universe = self.max_universe.max(u); } From b202d6f6b2b0dee78554c0433560a8c54ad86c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 1 Sep 2026 15:20:44 +0200 Subject: [PATCH 29/31] better document various functions around resolve --- compiler/rustc_infer/src/infer/mod.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 75f7bb7fcd9ec..b76dc226b62b3 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1247,6 +1247,25 @@ impl<'tcx> InferCtxt<'tcx> { } } + /// Resolve a type variable. Resolving means the following: + /// + /// - If a `Ty` is a rigid type (like, an integer, or some ADT), do nothing. + /// - If a `Ty` is a type infer variable, but has been equated with an actual type, + /// return that type. + /// - If a `Ty` is an int or float infer variable, and has been equated with an integer + /// or floating point type, return that type. + /// - If a `Ty` is any kind of infer variable that has been equated, but not yet with a rigid + /// type, then this set of equated variables forms an equivalence class. One of the variables + /// in that equivalent class is said to be the root variable, and resolving makes sure to + /// consistently return this root variable. This is beneficial for caching. + /// This behavior, of returning roots, changed in . + /// + /// Otherwise, resolving simply does nothing. + /// + /// The "shallow" part of the name refers to the fact that types may themselves contain more + /// type variables. e.g. The field types of a struct. `shallow_resolve` does not recurse into + /// these nested variables. If that's what you want, use [`deeply_resolve_ignoring_regions`](Self::deeply_resolve_ignoring_regions), + /// or better [`deeply_resolve`](rustc_type_ir::deeply_resolve), if you can, which *does* resolve regions. pub fn shallow_resolve(&self, ty: Ty<'tcx>) -> Ty<'tcx> { if let ty::Infer(v) = *ty.kind() { match v { @@ -1312,6 +1331,8 @@ impl<'tcx> InferCtxt<'tcx> { } } + /// See docs on [`shallow_resolve`](Self::shallow_resolve) for more explanation. + /// It's the same, but for consts. pub fn shallow_resolve_const(&self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { match ct.kind() { ty::ConstKind::Infer(infer_ct) => match infer_ct { @@ -1338,6 +1359,8 @@ impl<'tcx> InferCtxt<'tcx> { } } + /// See docs on [`shallow_resolve`](Self::shallow_resolve) for more explanation. + /// It's the same, but for terms (types or consts). pub fn shallow_resolve_term(&self, term: ty::Term<'tcx>) -> ty::Term<'tcx> { match term.kind() { ty::TermKind::Ty(ty) => self.shallow_resolve(ty).into(), @@ -1404,7 +1427,7 @@ impl<'tcx> InferCtxt<'tcx> { } } - /// Resolves a float var to a rigid int type, if it was constrained to one, + /// Resolves a float var to a rigid type, if it was constrained to one, /// or else the root float var in the unification table. pub fn shallow_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> { let mut inner = self.inner.borrow_mut(); From 670f799b5549939321ba51adf5dc165368d4a658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 1 Sep 2026 15:45:24 +0200 Subject: [PATCH 30/31] make `deeply_resolve` a method on InferCtxtLike --- .../src/infer/outlives/obligations.rs | 11 ++++-- .../src/canonical/mod.rs | 4 +-- .../rustc_next_trait_solver/src/normalize.rs | 10 +++--- .../src/solve/eval_ctxt/mod.rs | 10 +++--- .../src/solve/inspect/analyse.rs | 16 +++++++-- compiler/rustc_type_ir/src/infer_ctxt.rs | 34 ++++++++----------- 6 files changed, 48 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index ff9d66588fe78..314867a5ed3ad 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -66,7 +66,7 @@ use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::outlives::{Component, push_outlives_components}; use rustc_middle::ty::{ self, GenericArgKind, GenericArgsRef, PolyTypeOutlivesClause, Region, RegionVid, Ty, TyCtxt, - TypeVisitableExt, Upcast, deeply_resolve_via_unification_table, + TypeVisitableExt, Upcast, }; use rustc_span::Span; use rustc_type_ir::region_constraint::{self, LeafRegionConstraint}; @@ -345,6 +345,8 @@ impl<'tcx> InferCtxt<'tcx> { outlives_env: &OutlivesEnvironment<'tcx>, span: Span, ) { + use rustc_type_ir::InferCtxtLike; + assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot"); if self.tcx.assumptions_on_binders() { @@ -371,7 +373,12 @@ impl<'tcx> InferCtxt<'tcx> { // `TypeOutlives` is structural, so we should try to opportunistically resolve all // region vids before processing regions, so we have a better chance to match clauses // in our param-env. - let (sup_type, sub_region) = deeply_resolve_via_unification_table(self, (sup_type, sub_region)); + // + // We *want* this folder to live in `rustc_type_ir`. Our best way to call into it is + // through `InferCtxtLike` and it is not defined as an inherent method on `InferCtxt`. + #[allow(rustc::usage_of_type_ir_traits)] + let (sup_type, sub_region) = + self.deeply_resolve_via_unification_table((sup_type, sub_region)); if self.tcx.sess.opts.unstable_opts.higher_ranked_assumptions && outlives_env diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index c8e880cf8a7dc..c60e6ee246273 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -19,7 +19,7 @@ use rustc_type_ir::relate::{ }; use rustc_type_ir::{ self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner, Region, - TypeFoldable, TypingMode, TypingModeEqWrapper, deeply_resolve_via_unification_table, + TypeFoldable, TypingMode, TypingModeEqWrapper, }; use thin_vec::ThinVec; use tracing::instrument; @@ -568,7 +568,7 @@ where { let var_values = CanonicalVarValues { var_values: delegate.cx().mk_args(var_values) }; let state = inspect::State { var_values, data }; - let state = deeply_resolve_via_unification_table(&**delegate, state); + let state = delegate.deeply_resolve_via_unification_table(state); Canonicalizer::canonicalize_response(delegate, max_input_universe, state) } diff --git a/compiler/rustc_next_trait_solver/src/normalize.rs b/compiler/rustc_next_trait_solver/src/normalize.rs index 8145be2ed2c7f..ab3a92da4ba54 100644 --- a/compiler/rustc_next_trait_solver/src/normalize.rs +++ b/compiler/rustc_next_trait_solver/src/normalize.rs @@ -3,7 +3,7 @@ use std::fmt::Debug; use rustc_type_ir::inherent::*; use rustc_type_ir::{ self as ty, AliasTerm, Binder, FallibleTypeFolder, InferCtxtLike, Interner, PredicateProxy, - TypeFoldable, TypeSuperFoldable, TypeVisitableExt, UniverseIndex, deeply_resolve_via_unification_table, + TypeFoldable, TypeSuperFoldable, TypeVisitableExt, UniverseIndex, }; use tracing::instrument; @@ -139,8 +139,8 @@ where if self.cx().renormalize_rigid_aliases() && orig_is_rigid == ty::IsRigid::Yes { // find out missing typing env change. - let original = deeply_resolve_via_unification_table(infcx, original); - let normalized = deeply_resolve_via_unification_table(infcx, normalized); + let original = infcx.deeply_resolve_via_unification_table(original); + let normalized = infcx.deeply_resolve_via_unification_table(normalized); assert_eq!(original, normalized, "rigid alias is further normalized"); } Ok(normalized) @@ -189,8 +189,8 @@ where if self.cx().renormalize_rigid_aliases() && orig_is_rigid == ty::IsRigid::Yes { // find out missing typing env change. - let original = deeply_resolve_via_unification_table(infcx, original); - let normalized = deeply_resolve_via_unification_table(infcx, normalized); + let original = infcx.deeply_resolve_via_unification_table(original); + let normalized = infcx.deeply_resolve_via_unification_table(normalized); assert_eq!(original, normalized, "rigid alias is further normalized"); } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index abb328f11cc56..e7159fa6a1805 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -19,8 +19,7 @@ use rustc_type_ir::solve::{ use rustc_type_ir::{ self as ty, CanonicalVarValues, ClauseKind, InferCtxtLike, Interner, MayBeErased, OpaqueTypeKey, PredicateKind, PredicateProxy, Region, RegionVid, TypeFoldable, - TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, deeply_resolve_via_unification_table, - max_universe, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, max_universe, }; use thin_vec::ThinVec; use tracing::{Level, debug, instrument, trace, warn}; @@ -659,7 +658,8 @@ where // so we only canonicalize the lookup table and ignore // duplicate entries. let opaque_types = self.delegate.clone_opaque_types_lookup_table(); - let (goal, opaque_types) = deeply_resolve_via_unification_table(&**self.delegate, (goal, opaque_types)); + + let (goal, opaque_types) = self.delegate.deeply_resolve_via_unification_table((goal, opaque_types)); let typing_mode = self.typing_mode(); let step_kind = self.step_kind_for_source(source); @@ -1605,7 +1605,7 @@ where let external_constraints = self.compute_external_query_constraints(certainty, normalization_nested_goals); let (var_values, mut external_constraints) = - deeply_resolve_via_unification_table(&**self.delegate, (self.var_values, external_constraints)); + self.delegate.deeply_resolve_via_unification_table((self.var_values, external_constraints)); // Remove any trivial or duplicated region constraints once we've resolved regions let mut unique = HashSet::default(); @@ -1929,7 +1929,7 @@ pub(super) fn evaluate_root_goal_for_proof_tree, root_depth: usize, ) -> (Result, NoSolution>, inspect::GoalEvaluation) { let opaque_types = delegate.clone_opaque_types_lookup_table(); - let (goal, opaque_types) = deeply_resolve_via_unification_table(&**delegate, (goal, opaque_types)); + let (goal, opaque_types) = delegate.deeply_resolve_via_unification_table((goal, opaque_types)); let typing_mode = delegate.typing_mode_raw().assert_not_erased(); let (orig_values, canonical_goal) = diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 829068461d295..8c8af70f4af46 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -14,7 +14,7 @@ use std::assert_matches; use rustc_infer::infer::InferCtxt; use rustc_macros::extension; use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult}; -use rustc_middle::ty::{RequiredDepth, TyCtxt, VisitorResult, deeply_resolve_via_unification_table, try_visit}; +use rustc_middle::ty::{RequiredDepth, TyCtxt, VisitorResult, try_visit}; use rustc_middle::{bug, ty}; use rustc_next_trait_solver::canonical::instantiate_canonical_state; use rustc_next_trait_solver::solve::{MaybeCause, MaybeInfo, SolverDelegateEvalExt as _, inspect}; @@ -145,6 +145,8 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { fields(goal = ?self.goal.goal, steps = ?self.steps) )] pub fn instantiate_impl_args(&self, span: Span) -> ty::GenericArgsRef<'tcx> { + use rustc_middle::ty::InferCtxtLike; + let infcx = self.goal.infcx; let param_env = self.goal.goal.param_env; let mut orig_values = self.goal.orig_values.clone(); @@ -170,7 +172,10 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { self.final_state, ); - return deeply_resolve_via_unification_table(&**infcx, impl_args); + // We *want* this folder to live in `rustc_type_ir`. Our best way to call into it is + // through `InferCtxtLike` and it is not defined as an inherent method on `InferCtxt`. + #[allow(rustc::usage_of_type_ir_traits)] + return infcx.deeply_resolve_via_unification_table(impl_args); } inspect::ProbeStep::AddGoal(..) => {} inspect::ProbeStep::MakeCanonicalResponse { .. } @@ -342,6 +347,8 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { root: inspect::GoalEvaluation>, source: GoalSource, ) -> Self { + use rustc_middle::ty::InferCtxtLike; + let infcx = <&SolverDelegate<'tcx>>::from(infcx); let prev_universe = infcx.universe(); @@ -361,7 +368,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { depth, orig_values, prev_universe, - goal: deeply_resolve_via_unification_table(&**infcx, uncanonicalized_goal), + // We *want* this folder to live in `rustc_type_ir`. Our best way to call into it is + // through `InferCtxtLike` and it is not defined as an inherent method on `InferCtxt`. + #[allow(rustc::usage_of_type_ir_traits)] + goal: infcx.deeply_resolve_via_unification_table(uncanonicalized_goal), result, final_revision, source, diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 55a88b0632d47..a86a07edb902f 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -576,6 +576,20 @@ pub trait InferCtxtLike: Sized { ); fn reset_opaque_types(&self); + + /// Where possible, replaces type/const/region variables in `value` with their final value. + /// If a type/const/region variable has not (yet) been unified, it is left as is. + /// + /// This is an idempotent operation that does not affect inference state in any way, + /// which means it's safe to call this function at will. + fn deeply_resolve_via_unification_table>(&self, value: T) -> T { + if value.has_infer() { + let mut folder = DeepVariableResolver::new(self); + value.fold_with(&mut folder) + } else { + value + } + } } pub fn may_use_unstable_feature<'a, I: Interner, Infcx>( @@ -622,26 +636,6 @@ where } } -/// Where possible, replaces type/const/region variables in `value` with their final value. -/// If a type/const/region variable has not (yet) been unified, it is left as is. -/// -/// This is an idempotent operation that does not affect inference state in any way, -/// which means it's safe to call this function at will. -pub fn deeply_resolve_via_unification_table< - Infcx: InferCtxtLike, - T: TypeFoldable, ->( - infcx: &Infcx, - value: T, -) -> T { - if value.has_infer() { - let mut folder = DeepVariableResolver::new(infcx); - value.fold_with(&mut folder) - } else { - value - } -} - struct DeepVariableResolver<'a, D, I = ::Interner> where D: InferCtxtLike, From 532134ebf68bd96b315aa515d111f4f06730f56b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 1 Sep 2026 15:52:59 +0200 Subject: [PATCH 31/31] rename fully_resolve to deeply_resolve_and_assert_fully_resolved --- .../rustc_hir_analysis/src/check/compare_impl_item.rs | 2 +- .../src/check/compare_impl_item/refine.rs | 4 +++- .../src/impl_wf_check/min_specialization.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 7 +++++-- compiler/rustc_infer/src/infer/resolve.rs | 2 +- .../rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs | 8 +++++--- compiler/rustc_trait_selection/src/traits/mod.rs | 2 +- 7 files changed, 17 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index c95638629adde..41766ceec1bee 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -708,7 +708,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( let mut remapped_types = DefIdMap::default(); for (def_id, (ty, args)) in collected_types { - match infcx.fully_resolve(ty) { + match infcx.deeply_resolve_via_region_graph(ty) { Ok(ty) => { // `ty` contains free regions that we created earlier while liberating the // trait fn signature. However, projection normalization expects `ty` to diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 5a6a718b8cc12..471be6043ed65 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -189,7 +189,9 @@ pub(crate) fn check_refining_return_position_impl_trait_in_trait<'tcx>( return; } // Resolve any lifetime variables that may have been introduced during normalization. - let Ok((trait_bounds, impl_bounds)) = infcx.fully_resolve((trait_bounds, impl_bounds)) else { + let Ok((trait_bounds, impl_bounds)) = + infcx.deeply_resolve_via_region_graph((trait_bounds, impl_bounds)) + else { // If resolution didn't fully complete, we cannot continue checking RPITIT refinement, and // delay a bug as the original code contains load-bearing errors. tcx.dcx().delayed_bug("encountered errors when checking RPITIT refinement (resolution)"); diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index cec65615111a7..d56c094f9f5c3 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -191,7 +191,7 @@ fn get_impl_args( let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl1_def_id)?; ocx.resolve_regions_and_report_errors(impl1_def_id, param_env, assumed_wf_types)?; - let Ok(impl2_args) = infcx.fully_resolve(impl2_args) else { + let Ok(impl2_args) = infcx.deeply_resolve_via_region_graph(impl2_args) else { let span = tcx.def_span(impl1_def_id); let guar = tcx.dcx().emit_err(GenericArgsOnOverriddenImpl { span }); return Err(guar); diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index b76dc226b62b3..62ea982df9e0b 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1488,8 +1488,11 @@ impl<'tcx> InferCtxt<'tcx> { /// /// This method is idempotent, but it not typically not invoked /// except during the writeback phase. - pub fn fully_resolve>>(&self, value: T) -> FixupResult { - match resolve::fully_resolve(self, value) { + pub fn deeply_resolve_via_region_graph>>( + &self, + value: T, + ) -> FixupResult { + match resolve::deeply_resolve_via_region_graph(self, value) { Ok(value) => { if value.has_non_region_infer() { bug!("`{value:?}` is not fully resolved"); diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index f78e1d5b2d3b2..1ced1b336c817 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -124,7 +124,7 @@ impl<'a, 'tcx> TypeFolder> for DeepRegionResolver<'a, 'tcx> { /// Full type resolution replaces all type and region variables with /// their concrete results. If any variable cannot be replaced (never unified, etc) /// then an `Err` result is returned. -pub fn fully_resolve<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> FixupResult +pub fn deeply_resolve_via_region_graph<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> FixupResult where T: TypeFoldable>, { diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index e7159fa6a1805..61cd8e46d8816 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -659,7 +659,8 @@ where // duplicate entries. let opaque_types = self.delegate.clone_opaque_types_lookup_table(); - let (goal, opaque_types) = self.delegate.deeply_resolve_via_unification_table((goal, opaque_types)); + let (goal, opaque_types) = + self.delegate.deeply_resolve_via_unification_table((goal, opaque_types)); let typing_mode = self.typing_mode(); let step_kind = self.step_kind_for_source(source); @@ -1604,8 +1605,9 @@ where let external_constraints = self.compute_external_query_constraints(certainty, normalization_nested_goals); - let (var_values, mut external_constraints) = - self.delegate.deeply_resolve_via_unification_table((self.var_values, external_constraints)); + let (var_values, mut external_constraints) = self + .delegate + .deeply_resolve_via_unification_table((self.var_values, external_constraints)); // Remove any trivial or duplicated region constraints once we've resolved regions let mut unique = HashSet::default(); diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 155cb6d6bbb02..aa676dab91bbc 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -406,7 +406,7 @@ fn do_normalize_clauses<'tcx>( // caller sites. We should also avoid cloning if possible. let normalized_env = ty::ParamEnv::new(tcx, clauses.iter().copied()); let _errors = infcx.resolve_regions(cause.body_def_id, normalized_env, []); - match infcx.fully_resolve(clauses.clone()) { + match infcx.deeply_resolve_via_region_graph(clauses.clone()) { Ok(clauses) => clauses, Err(fixup_err) => { // The first folder only replaces infers from normalization failure. We might not have