From 189305eda3d5be1d7dbc9002bfd9a0b27478c3ac Mon Sep 17 00:00:00 2001 From: Jacob Adam Date: Sun, 12 Apr 2026 23:21:13 +0100 Subject: [PATCH 01/11] Skip the closure signature annotation check for tainted bodies When a coroutine has too many parameters, `check_match` fails and `construct_error` builds a MIR body with only the coroutine's computed args (env + resume type). The user-provided signature, however, still reflects all the parameters the user wrote. `check_signature_annotation` then tries to `zip_eq` these two mismatched iterators, causing a panic. Checking `tainted_by_errors` and bailing early avoids this, since `construct_error` bodies cannot meaningfully be compared against user annotations. --- compiler/rustc_borrowck/src/type_check/input_output.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 4e762b368496d..39b3e525bc4c2 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -32,6 +32,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { return; } + // If the MIR body was constructed via `construct_error` (because an + // earlier pass like match checking failed), its args may not match + // the user-provided signature (e.g. a coroutine with too many + // parameters). Bail out as this can cause panic, + // see . + if self.body.tainted_by_errors.is_some() { + return; + } + let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id); // Instantiate the canonicalized variables from user-provided signature From d14be60b5d6a3b6470e553561ca7c269201e93b7 Mon Sep 17 00:00:00 2001 From: Jacob Adam Date: Sun, 12 Apr 2026 23:22:43 +0100 Subject: [PATCH 02/11] Convert the regression test for a coroutine ICE from a crash test to an UI test --- tests/crashes/139570.rs | 4 ---- tests/ui/coroutine/too-many-parameters-ice.rs | 13 +++++++++++++ .../coroutine/too-many-parameters-ice.stderr | 18 ++++++++++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) delete mode 100644 tests/crashes/139570.rs create mode 100644 tests/ui/coroutine/too-many-parameters-ice.rs create mode 100644 tests/ui/coroutine/too-many-parameters-ice.stderr diff --git a/tests/crashes/139570.rs b/tests/crashes/139570.rs deleted file mode 100644 index 9c001aaf848aa..0000000000000 --- a/tests/crashes/139570.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: #139570 -fn main() { - |(1, 42), ()| yield; -} diff --git a/tests/ui/coroutine/too-many-parameters-ice.rs b/tests/ui/coroutine/too-many-parameters-ice.rs new file mode 100644 index 0000000000000..3508393120471 --- /dev/null +++ b/tests/ui/coroutine/too-many-parameters-ice.rs @@ -0,0 +1,13 @@ +//! Regression test for . +//! A coroutine with too many parameters should emit errors without an ICE. + +#![feature(coroutines)] + +fn main() { + #[coroutine] + |(1, 42), ()| { + //~^ ERROR too many parameters for a coroutine + //~| ERROR refutable pattern in closure argument + yield + }; +} diff --git a/tests/ui/coroutine/too-many-parameters-ice.stderr b/tests/ui/coroutine/too-many-parameters-ice.stderr new file mode 100644 index 0000000000000..93d995b1888c6 --- /dev/null +++ b/tests/ui/coroutine/too-many-parameters-ice.stderr @@ -0,0 +1,18 @@ +error[E0628]: too many parameters for a coroutine (expected 0 or 1 parameters) + --> $DIR/too-many-parameters-ice.rs:8:5 + | +LL | |(1, 42), ()| { + | ^^^^^^^^^^^^^ + +error[E0005]: refutable pattern in closure argument + --> $DIR/too-many-parameters-ice.rs:8:6 + | +LL | |(1, 42), ()| { + | ^^^^^^^ patterns `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered + | + = note: the matched value is of type `(i32, i32)` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0005, E0628. +For more information about an error, try `rustc --explain E0005`. From 1e02a2b10bccb95cd0962ac79f75f63e8599aa8e Mon Sep 17 00:00:00 2001 From: thebabalola Date: Mon, 13 Apr 2026 23:07:39 +0100 Subject: [PATCH 03/11] Add test for list item leading whitespace trimming --- .../rustc_errors/src/markdown/tests/parse.rs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/compiler/rustc_errors/src/markdown/tests/parse.rs b/compiler/rustc_errors/src/markdown/tests/parse.rs index 807fda3211799..1a8d19a1136e7 100644 --- a/compiler/rustc_errors/src/markdown/tests/parse.rs +++ b/compiler/rustc_errors/src/markdown/tests/parse.rs @@ -377,3 +377,24 @@ fn test_codeblock_trailing_whitespace() { assert_eq!(t, MdTree::CodeBlock { txt: "code\n```abc\nrest", lang: Some("rust") }); assert_eq!(r, b""); } + +#[test] +fn test_list_item_leading_whitespace() { + // extra spaces after marker + let buf = "- hello"; + let (t, r) = parse_unordered_li(buf.as_bytes()); + assert_eq!(t, MdTree::UnorderedListItem(vec![MdTree::PlainText("hello")].into())); + assert_eq!(r, b""); + + // tab after the marker space + let buf = "- \thello"; + let (t, r) = parse_unordered_li(buf.as_bytes()); + assert_eq!(t, MdTree::UnorderedListItem(vec![MdTree::PlainText("hello")].into())); + assert_eq!(r, b""); + + // ordered list + let buf = "1. hello"; + let (t, r) = parse_ordered_li(buf.as_bytes()); + assert_eq!(t, MdTree::OrderedListItem(1, vec![MdTree::PlainText("hello")].into())); + assert_eq!(r, b""); +} From fdfdb0837c77d564f072d6efa1cfea6a46261d08 Mon Sep 17 00:00:00 2001 From: thebabalola Date: Mon, 13 Apr 2026 23:07:39 +0100 Subject: [PATCH 04/11] Replace custom trim_ascii_start with the standard library method The local trim_ascii_start function in the markdown parser duplicates <[u8]>::trim_ascii_start() from the standard library (stable since 1.80). Remove the custom function and call the stdlib method directly. No behaviour change. Fixes https://github.com/rustfoundation/interop-initiative/issues/53 --- compiler/rustc_errors/src/markdown/parse.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_errors/src/markdown/parse.rs b/compiler/rustc_errors/src/markdown/parse.rs index 6512d9ce19974..cd39f9b34d43a 100644 --- a/compiler/rustc_errors/src/markdown/parse.rs +++ b/compiler/rustc_errors/src/markdown/parse.rs @@ -252,7 +252,7 @@ fn parse_heading(buf: &[u8]) -> ParseResult<'_> { fn parse_unordered_li(buf: &[u8]) -> Parsed<'_> { let (txt, rest) = get_indented_section(&buf[2..]); let ctx = Context { .. }; - let stream = parse_recursive(trim_ascii_start(txt), ctx); + let stream = parse_recursive(txt.trim_ascii_start(), ctx); (MdTree::UnorderedListItem(stream), rest) } @@ -261,7 +261,7 @@ fn parse_ordered_li(buf: &[u8]) -> Parsed<'_> { let (num, pos) = ord_list_start(buf).unwrap(); // success tested in caller let (txt, rest) = get_indented_section(&buf[pos..]); let ctx = Context { .. }; - let stream = parse_recursive(trim_ascii_start(txt), ctx); + let stream = parse_recursive(txt.trim_ascii_start(), ctx); (MdTree::OrderedListItem(num, stream), rest) } @@ -578,12 +578,6 @@ fn trim_extra_ws(mut txt: &str) -> &str { &txt[..txt.len() - end_ws] } -/// If there is more than one whitespace char at start, trim the extras -fn trim_ascii_start(buf: &[u8]) -> &[u8] { - let count = buf.iter().take_while(|ch| ch.is_ascii_whitespace()).count(); - &buf[count..] -} - #[cfg(test)] #[path = "tests/parse.rs"] mod tests; From 7114404a26b196e8161df15f744cdefc21875d91 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 18 Mar 2026 16:49:58 +0300 Subject: [PATCH 05/11] ast: Preserve the star symbol span in glob delegation items --- compiler/rustc_ast/src/ast.rs | 9 +++++++-- compiler/rustc_ast/src/visit.rs | 1 + compiler/rustc_ast_pretty/src/pprust/state/item.rs | 10 ++++++++-- compiler/rustc_expand/src/expand.rs | 8 ++++---- compiler/rustc_parse/src/parser/item.rs | 13 +++++++++---- 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index ad32fe7e488c1..b2c573c23f891 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3901,12 +3901,17 @@ pub struct Delegation { pub from_glob: bool, } +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub enum DelegationSuffixes { + List(ThinVec<(Ident, Option)>), + Glob(Span), +} + #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct DelegationMac { pub qself: Option>, pub prefix: Path, - // Some for list delegation, and None for glob delegation. - pub suffixes: Option)>>, + pub suffixes: DelegationSuffixes, pub body: Option>, } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 6aa8d5f38ad24..ee4b1d1354300 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -430,6 +430,7 @@ macro_rules! common_visitor_and_walkers { Defaultness, Delegation, DelegationMac, + DelegationSuffixes, DelimArgs, DelimSpan, EnumDef, diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 201fa63bfa33c..cb9bbf014e013 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -444,7 +444,10 @@ impl<'a> State<'a> { &item.vis, &deleg.qself, &deleg.prefix, - deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)), + match &deleg.suffixes { + ast::DelegationSuffixes::List(s) => DelegationKind::List(s), + ast::DelegationSuffixes::Glob(_) => DelegationKind::Glob, + }, &deleg.body, ), } @@ -651,7 +654,10 @@ impl<'a> State<'a> { vis, &deleg.qself, &deleg.prefix, - deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)), + match &deleg.suffixes { + ast::DelegationSuffixes::List(s) => DelegationKind::List(s), + ast::DelegationSuffixes::Glob(_) => DelegationKind::Glob, + }, &deleg.body, ), } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 9f5a01452fdc3..92efab3212ab3 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -8,9 +8,9 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list}; use rustc_ast::{ self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrItemKind, AttrStyle, AttrVec, - DUMMY_NODE_ID, EarlyParsedAttribute, ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, - ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind, NodeId, PatKind, StmtKind, - TyKind, token, + DUMMY_NODE_ID, DelegationSuffixes, EarlyParsedAttribute, ExprKind, ForeignItemKind, HasAttrs, + HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind, NodeId, + PatKind, StmtKind, TyKind, token, }; use rustc_ast_pretty::pprust; use rustc_attr_parsing::parser::AllowExprMetavar; @@ -2401,7 +2401,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { res } None if let Some((deleg, item)) = node.delegation() => { - let Some(suffixes) = &deleg.suffixes else { + let DelegationSuffixes::List(suffixes) = &deleg.suffixes else { let traitless_qself = matches!(&deleg.qself, Some(qself) if qself.position == 0); let (item, of_trait) = match node.to_annotatable() { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index df85aa7d041a5..ccfc9438f1ccf 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -857,7 +857,7 @@ impl<'a> Parser<'a> { kind: AssocItemKind::DelegationMac(Box::new(DelegationMac { qself: None, prefix: of_trait.trait_ref.path.clone(), - suffixes: None, + suffixes: DelegationSuffixes::Glob(whole_reuse_span), body, })), })); @@ -879,10 +879,12 @@ impl<'a> Parser<'a> { Ok(if self.eat_path_sep() { let suffixes = if self.eat(exp!(Star)) { - None + DelegationSuffixes::Glob(self.prev_token.span) } else { let parse_suffix = |p: &mut Self| Ok((p.parse_path_segment_ident()?, rename(p)?)); - Some(self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), parse_suffix)?.0) + DelegationSuffixes::List( + self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), parse_suffix)?.0, + ) }; ItemKind::DelegationMac(Box::new(DelegationMac { @@ -1519,7 +1521,10 @@ impl<'a> Parser<'a> { let span = self.psess.source_map().guess_head_span(span); let descr = kind.descr(); let help = match kind { - ItemKind::DelegationMac(deleg) if deleg.suffixes.is_none() => false, + ItemKind::DelegationMac(box DelegationMac { + suffixes: DelegationSuffixes::Glob(_), + .. + }) => false, _ => true, }; self.dcx().emit_err(errors::BadItemKind { span, descr, ctx, help }); From 8114c5dc2e5c578eb11246a56cc640e1bdc001db Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 18 Mar 2026 17:30:57 +0300 Subject: [PATCH 06/11] expand: More precise location for glob delegation The span location of the last segment in the desugared path is inherited from the star symbol's span --- compiler/rustc_expand/src/base.rs | 11 +++++++-- compiler/rustc_resolve/src/macros.rs | 23 ++++++++++++------- .../delegation/impl-reuse-negative-traits.rs | 2 +- .../impl-reuse-negative-traits.stderr | 6 ++--- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 7fd891395fa02..fd685f534da18 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1019,18 +1019,24 @@ impl SyntaxExtension { pub fn glob_delegation( trait_def_id: DefId, impl_def_id: LocalDefId, + star_span: Span, edition: Edition, ) -> SyntaxExtension { struct GlobDelegationExpanderImpl { trait_def_id: DefId, impl_def_id: LocalDefId, + star_span: Span, } impl GlobDelegationExpander for GlobDelegationExpanderImpl { fn expand( &self, ecx: &mut ExtCtxt<'_>, ) -> ExpandResult)>, ()> { - match ecx.resolver.glob_delegation_suffixes(self.trait_def_id, self.impl_def_id) { + match ecx.resolver.glob_delegation_suffixes( + self.trait_def_id, + self.impl_def_id, + self.star_span, + ) { Ok(suffixes) => ExpandResult::Ready(suffixes), Err(Indeterminate) if ecx.force_mode => ExpandResult::Ready(Vec::new()), Err(Indeterminate) => ExpandResult::Retry(()), @@ -1038,7 +1044,7 @@ impl SyntaxExtension { } } - let expander = GlobDelegationExpanderImpl { trait_def_id, impl_def_id }; + let expander = GlobDelegationExpanderImpl { trait_def_id, impl_def_id, star_span }; SyntaxExtension::default(SyntaxExtensionKind::GlobDelegation(Arc::new(expander)), edition) } @@ -1170,6 +1176,7 @@ pub trait ResolverExpand { &self, trait_def_id: DefId, impl_def_id: LocalDefId, + star_span: Span, ) -> Result)>, Indeterminate>; /// Record the name of an opaque `Ty::ImplTrait` pre-expansion so that it can be used diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 13bda9c98c0a7..f0e757b2d673d 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -4,7 +4,7 @@ use std::mem; use std::sync::Arc; -use rustc_ast::{self as ast, Crate, DUMMY_NODE_ID, NodeId}; +use rustc_ast::{self as ast, Crate, DUMMY_NODE_ID, DelegationSuffixes, NodeId}; use rustc_ast_pretty::pprust; use rustc_attr_parsing::AttributeParser; use rustc_errors::{Applicability, DiagCtxtHandle, StashKey}; @@ -286,7 +286,8 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive), InvocationKind::GlobDelegation { ref item, .. } => { let ast::AssocItemKind::DelegationMac(deleg) = &item.kind else { unreachable!() }; - deleg_impl = Some(self.invocation_parent(invoc_id)); + let DelegationSuffixes::Glob(star_span) = deleg.suffixes else { unreachable!() }; + deleg_impl = Some((self.invocation_parent(invoc_id), star_span)); // It is sufficient to consider glob delegation a bang macro for now. (&deleg.prefix, MacroKind::Bang) } @@ -530,6 +531,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { &self, trait_def_id: DefId, impl_def_id: LocalDefId, + star_span: Span, ) -> Result)>, Indeterminate> { let target_trait = self.expect_module(trait_def_id); if !target_trait.unexpanded_invocations.borrow().is_empty() { @@ -549,13 +551,13 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { let mut idents = Vec::new(); target_trait.for_each_child(self, |this, ident, orig_ident_span, ns, _binding| { - // FIXME: Adjust hygiene for idents from globs, like for glob imports. if let Some(overriding_keys) = this.impl_binding_keys.get(&impl_def_id) && overriding_keys.contains(&BindingKey::new(ident, ns)) { // The name is overridden, do not produce it from the glob delegation. } else { - idents.push((ident.orig(orig_ident_span), None)); + // FIXME: Adjust hygiene for idents from globs, like for glob imports. + idents.push((ident.orig(star_span.with_ctxt(orig_ident_span.ctxt())), None)); } }); Ok(idents) @@ -579,7 +581,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, node_id: NodeId, force: bool, - deleg_impl: Option, + deleg_impl: Option<(LocalDefId, Span)>, invoc_in_mod_inert_attr: Option, suggestion_span: Option, ) -> Result<(Arc, Res), Indeterminate> { @@ -792,7 +794,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { kind: MacroKind, parent_scope: &ParentScope<'ra>, force: bool, - deleg_impl: Option, + deleg_impl: Option<(LocalDefId, Span)>, invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, ignore_import: Option>, suggestion_span: Option, @@ -877,10 +879,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let res = res?; let ext = match deleg_impl { - Some(impl_def_id) => match res { + Some((impl_def_id, star_span)) => match res { def::Res::Def(DefKind::Trait, def_id) => { let edition = self.tcx.sess.edition(); - Some(Arc::new(SyntaxExtension::glob_delegation(def_id, impl_def_id, edition))) + Some(Arc::new(SyntaxExtension::glob_delegation( + def_id, + impl_def_id, + star_span, + edition, + ))) } _ => None, }, diff --git a/tests/ui/delegation/impl-reuse-negative-traits.rs b/tests/ui/delegation/impl-reuse-negative-traits.rs index 7bcbc82f03db8..8bc2b72708599 100644 --- a/tests/ui/delegation/impl-reuse-negative-traits.rs +++ b/tests/ui/delegation/impl-reuse-negative-traits.rs @@ -4,7 +4,6 @@ trait Trait { fn foo(&self); - //~^ ERROR negative impls cannot have any items [E0749] } struct S; @@ -15,5 +14,6 @@ impl Trait for S { struct F(S); reuse impl !Trait for F { &self.0 } +//~^ ERROR negative impls cannot have any items fn main() {} diff --git a/tests/ui/delegation/impl-reuse-negative-traits.stderr b/tests/ui/delegation/impl-reuse-negative-traits.stderr index 1be6ef715920d..7510fdd89d7c6 100644 --- a/tests/ui/delegation/impl-reuse-negative-traits.stderr +++ b/tests/ui/delegation/impl-reuse-negative-traits.stderr @@ -1,8 +1,8 @@ error[E0749]: negative impls cannot have any items - --> $DIR/impl-reuse-negative-traits.rs:6:8 + --> $DIR/impl-reuse-negative-traits.rs:16:1 | -LL | fn foo(&self); - | ^^^ +LL | reuse impl !Trait for F { &self.0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error From 166c499a47b709f3f5c0d300ace5881f8ba12c54 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 18 Mar 2026 19:05:12 +0300 Subject: [PATCH 07/11] delegation: Give declaration of `self` syntax context of the delegation body Instead of the last segment of the delegation path. `self` is something that introduced by the whole delegation item, not some specific part of it, and the last segment may need to have a different context for path resolution purposes. --- compiler/rustc_resolve/src/late.rs | 3 +- tests/ui/delegation/impl-reuse-pass.rs | 25 ------- .../ui/delegation/impl-reuse-self-hygiene.rs | 28 ++++++++ .../delegation/impl-reuse-self-hygiene.stderr | 68 +++++++++++++++++++ 4 files changed, 97 insertions(+), 27 deletions(-) create mode 100644 tests/ui/delegation/impl-reuse-self-hygiene.rs create mode 100644 tests/ui/delegation/impl-reuse-self-hygiene.stderr diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 56e26b1ac6cbe..25ef573447c12 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3872,8 +3872,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let Some(body) = &delegation.body else { return }; self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| { - let span = delegation.path.segments.last().unwrap().ident.span; - let ident = Ident::new(kw::SelfLower, span.normalize_to_macro_rules()); + let ident = Ident::new(kw::SelfLower, body.span.normalize_to_macro_rules()); let res = Res::Local(delegation.id); this.innermost_rib_bindings(ValueNS).insert(ident, res); diff --git a/tests/ui/delegation/impl-reuse-pass.rs b/tests/ui/delegation/impl-reuse-pass.rs index 90060b03f9efd..578e8c08e7038 100644 --- a/tests/ui/delegation/impl-reuse-pass.rs +++ b/tests/ui/delegation/impl-reuse-pass.rs @@ -173,19 +173,6 @@ mod macros { macro_rules! m { () => { M } } reuse impl Trait for m!() { self_0_ref!(self) } - struct S1(u8); - macro_rules! one_line_reuse { ($self:ident) => { reuse impl Trait for S1 { $self.0 } } } - one_line_reuse!(self); - - struct S2(u8); - macro_rules! one_line_reuse_expr { ($x:expr) => { reuse impl Trait for S2 { $x } } } - one_line_reuse_expr!(self.0); - - struct S3(u8); - macro_rules! s3 { () => { S3 } } - macro_rules! one_line_reuse_expr2 { ($x:expr) => { reuse impl Trait for s3!() { $x } } } - one_line_reuse_expr2!(self.0); - fn f() { let s = S(1); s.foo(); @@ -194,18 +181,6 @@ mod macros { let m = M(41); m.foo(); m.bar(); - - let s1 = S1(2); - s1.foo(); - s1.bar(); - - let s2 = S2(4); - s2.foo(); - s2.bar(); - - let s3 = S3(5); - s3.foo(); - s3.bar(); } } diff --git a/tests/ui/delegation/impl-reuse-self-hygiene.rs b/tests/ui/delegation/impl-reuse-self-hygiene.rs new file mode 100644 index 0000000000000..b49e4419703a7 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-self-hygiene.rs @@ -0,0 +1,28 @@ +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +trait Trait { + fn foo(&self) -> u8 { 0 } + fn bar(&self) -> u8 { 1 } +} + +struct S1(u8); +macro_rules! one_line_reuse { ($self:ident) => { reuse impl Trait for S1 { $self.0 } } } +//~^ ERROR expected value, found module `self` +//~| ERROR expected value, found module `self` +one_line_reuse!(self); + +struct S2(u8); +macro_rules! one_line_reuse_expr { ($x:expr) => { reuse impl Trait for S2 { $x } } } +one_line_reuse_expr!(self.0); +//~^ ERROR expected value, found module `self` +//~| ERROR expected value, found module `self` + +struct S3(u8); +macro_rules! s3 { () => { S3 } } +macro_rules! one_line_reuse_expr2 { ($x:expr) => { reuse impl Trait for s3!() { $x } } } +one_line_reuse_expr2!(self.0); +//~^ ERROR expected value, found module `self` +//~| ERROR expected value, found module `self` + +fn main() {} diff --git a/tests/ui/delegation/impl-reuse-self-hygiene.stderr b/tests/ui/delegation/impl-reuse-self-hygiene.stderr new file mode 100644 index 0000000000000..ae93829809e4f --- /dev/null +++ b/tests/ui/delegation/impl-reuse-self-hygiene.stderr @@ -0,0 +1,68 @@ +error[E0424]: expected value, found module `self` + --> $DIR/impl-reuse-self-hygiene.rs:10:76 + | +LL | macro_rules! one_line_reuse { ($self:ident) => { reuse impl Trait for S1 { $self.0 } } } + | --------------------------^^^^^---- + | | | + | | `self` value is a keyword only available in methods with a `self` parameter + | `self` not allowed in an implementation +... +LL | one_line_reuse!(self); + | --------------------- in this macro invocation + | + = note: this error originates in the macro `one_line_reuse` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0424]: expected value, found module `self` + --> $DIR/impl-reuse-self-hygiene.rs:10:76 + | +LL | macro_rules! one_line_reuse { ($self:ident) => { reuse impl Trait for S1 { $self.0 } } } + | --------------------------^^^^^---- + | | | + | | `self` value is a keyword only available in methods with a `self` parameter + | `self` not allowed in an implementation +... +LL | one_line_reuse!(self); + | --------------------- in this macro invocation + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + = note: this error originates in the macro `one_line_reuse` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0424]: expected value, found module `self` + --> $DIR/impl-reuse-self-hygiene.rs:17:22 + | +LL | macro_rules! one_line_reuse_expr { ($x:expr) => { reuse impl Trait for S2 { $x } } } + | ------------------------------ `self` not allowed in an implementation +LL | one_line_reuse_expr!(self.0); + | ^^^^ `self` value is a keyword only available in methods with a `self` parameter + +error[E0424]: expected value, found module `self` + --> $DIR/impl-reuse-self-hygiene.rs:17:22 + | +LL | macro_rules! one_line_reuse_expr { ($x:expr) => { reuse impl Trait for S2 { $x } } } + | ------------------------------ `self` not allowed in an implementation +LL | one_line_reuse_expr!(self.0); + | ^^^^ `self` value is a keyword only available in methods with a `self` parameter + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0424]: expected value, found module `self` + --> $DIR/impl-reuse-self-hygiene.rs:24:23 + | +LL | macro_rules! one_line_reuse_expr2 { ($x:expr) => { reuse impl Trait for s3!() { $x } } } + | --------------------------------- `self` not allowed in an implementation +LL | one_line_reuse_expr2!(self.0); + | ^^^^ `self` value is a keyword only available in methods with a `self` parameter + +error[E0424]: expected value, found module `self` + --> $DIR/impl-reuse-self-hygiene.rs:24:23 + | +LL | macro_rules! one_line_reuse_expr2 { ($x:expr) => { reuse impl Trait for s3!() { $x } } } + | --------------------------------- `self` not allowed in an implementation +LL | one_line_reuse_expr2!(self.0); + | ^^^^ `self` value is a keyword only available in methods with a `self` parameter + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0424`. From f001d789c875d7b72487df22a6ac9dad04caacea Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 8 Apr 2026 14:59:53 +0300 Subject: [PATCH 08/11] Update some tests after rebase --- tests/ui/delegation/glob-glob-conflict.rs | 9 ++-- tests/ui/delegation/glob-glob-conflict.stderr | 50 +++++++++---------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/tests/ui/delegation/glob-glob-conflict.rs b/tests/ui/delegation/glob-glob-conflict.rs index cb07a78b84fef..c1cd3f703e07f 100644 --- a/tests/ui/delegation/glob-glob-conflict.rs +++ b/tests/ui/delegation/glob-glob-conflict.rs @@ -3,13 +3,10 @@ trait Trait1 { fn method(&self) -> u8; - //~^ ERROR: this function takes 1 argument but 0 arguments were supplied - //~| ERROR: mismatched types } trait Trait2 { fn method(&self) -> u8; - //~^ ERROR: this function takes 1 argument but 0 arguments were supplied - //~| ERROR: mismatched types + } trait Trait { fn method(&self) -> u8; @@ -28,10 +25,14 @@ impl Trait2 for u8 { impl Trait for u8 { reuse Trait1::*; reuse Trait2::*; //~ ERROR duplicate definitions with name `method` + //~^ ERROR: this function takes 1 argument but 0 arguments were supplied + //~| ERROR: mismatched types } impl Trait for u16 { reuse Trait1::*; reuse Trait1::*; //~ ERROR duplicate definitions with name `method` + //~^ ERROR: this function takes 1 argument but 0 arguments were supplied + //~| ERROR: mismatched types } fn main() {} diff --git a/tests/ui/delegation/glob-glob-conflict.stderr b/tests/ui/delegation/glob-glob-conflict.stderr index 4259d71117b7b..f55ee333630c6 100644 --- a/tests/ui/delegation/glob-glob-conflict.stderr +++ b/tests/ui/delegation/glob-glob-conflict.stderr @@ -1,5 +1,5 @@ error[E0201]: duplicate definitions with name `method`: - --> $DIR/glob-glob-conflict.rs:30:5 + --> $DIR/glob-glob-conflict.rs:27:5 | LL | fn method(&self) -> u8; | ----------------------- item in trait @@ -10,7 +10,7 @@ LL | reuse Trait2::*; | ^^^^^^^^^^^^^^^^ duplicate definition error[E0201]: duplicate definitions with name `method`: - --> $DIR/glob-glob-conflict.rs:34:5 + --> $DIR/glob-glob-conflict.rs:33:5 | LL | fn method(&self) -> u8; | ----------------------- item in trait @@ -21,35 +21,35 @@ LL | reuse Trait1::*; | ^^^^^^^^^^^^^^^^ duplicate definition error[E0061]: this function takes 1 argument but 0 arguments were supplied - --> $DIR/glob-glob-conflict.rs:10:8 + --> $DIR/glob-glob-conflict.rs:27:19 | -LL | fn method(&self) -> u8; - | ^^^^^^ argument #1 of type `&_` is missing +LL | reuse Trait2::*; + | ^ argument #1 of type `&_` is missing | note: method defined here - --> $DIR/glob-glob-conflict.rs:10:8 + --> $DIR/glob-glob-conflict.rs:8:8 | LL | fn method(&self) -> u8; | ^^^^^^ ---- help: provide the argument | -LL | fn method(/* value */)(&self) -> u8; - | +++++++++++++ +LL | reuse Trait2::*(/* value */); + | +++++++++++++ error[E0308]: mismatched types - --> $DIR/glob-glob-conflict.rs:10:8 + --> $DIR/glob-glob-conflict.rs:27:19 | -LL | fn method(&self) -> u8; - | ^^^^^^- help: consider using a semicolon here: `;` - | | - | expected `()`, found `u8` - | expected `()` because of default return type +LL | reuse Trait2::*; + | ^- help: consider using a semicolon here: `;` + | | + | expected `()`, found `u8` + | expected `()` because of default return type error[E0061]: this function takes 1 argument but 0 arguments were supplied - --> $DIR/glob-glob-conflict.rs:5:8 + --> $DIR/glob-glob-conflict.rs:33:19 | -LL | fn method(&self) -> u8; - | ^^^^^^ argument #1 of type `&_` is missing +LL | reuse Trait1::*; + | ^ argument #1 of type `&_` is missing | note: method defined here --> $DIR/glob-glob-conflict.rs:5:8 @@ -58,17 +58,17 @@ LL | fn method(&self) -> u8; | ^^^^^^ ---- help: provide the argument | -LL | fn method(/* value */)(&self) -> u8; - | +++++++++++++ +LL | reuse Trait1::*(/* value */); + | +++++++++++++ error[E0308]: mismatched types - --> $DIR/glob-glob-conflict.rs:5:8 + --> $DIR/glob-glob-conflict.rs:33:19 | -LL | fn method(&self) -> u8; - | ^^^^^^- help: consider using a semicolon here: `;` - | | - | expected `()`, found `u8` - | expected `()` because of default return type +LL | reuse Trait1::*; + | ^- help: consider using a semicolon here: `;` + | | + | expected `()`, found `u8` + | expected `()` because of default return type error: aborting due to 6 previous errors From 8619841f0586d14eb8daeba3bbee483a99ad3421 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Tue, 14 Apr 2026 10:57:46 +0200 Subject: [PATCH 09/11] limit duplicate-profiler-builtins test to targets that can do dynamic linking --- tests/run-make/duplicate-profiler-builtins/rmake.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-make/duplicate-profiler-builtins/rmake.rs b/tests/run-make/duplicate-profiler-builtins/rmake.rs index 2dc53d0ee59d0..1566bc667076a 100644 --- a/tests/run-make/duplicate-profiler-builtins/rmake.rs +++ b/tests/run-make/duplicate-profiler-builtins/rmake.rs @@ -2,6 +2,7 @@ // together without getting an error about duplicate profiler_builtins. //@ needs-profiler-runtime +//@ needs-dynamic-linking use run_make_support::{dynamic_lib_name, rustc}; From 778d27441d09ea17449433d34ebba5ec87c9a0ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 14 Apr 2026 10:47:37 +0200 Subject: [PATCH 10/11] also check let-else --- compiler/rustc_lint/src/internal.rs | 26 +++++++++++++++++-- .../internal-lints/must_match_exhaustively.rs | 3 +++ .../must_match_exhaustively.stderr | 20 ++++++++++++-- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index c0b113610f67a..d637390851d9d 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -783,7 +783,7 @@ impl<'tcx> LateLintPass<'tcx> for RustcMustMatchExhaustively { } } } - hir::ExprKind::If(expr, ..) if let ExprKind::Let(expr) = expr.kind => { + hir::ExprKind::Let(expr, ..) => { if let Some(attr_span) = is_rustc_must_match_exhaustively(cx, expr.init.hir_id) { cx.emit_span_lint( RUSTC_MUST_MATCH_EXHAUSTIVELY, @@ -791,7 +791,29 @@ impl<'tcx> LateLintPass<'tcx> for RustcMustMatchExhaustively { RustcMustMatchExhaustivelyNotExhaustive { attr_span, pat_span: expr.span, - message: "using if let only matches on one variant (try using `match`)", + message: "using `if let` only matches on one variant (try using `match`)", + }, + ); + } + } + _ => {} + } + } + + fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx rustc_hir::Stmt<'tcx>) { + match stmt.kind { + rustc_hir::StmtKind::Let(let_stmt) => { + if let_stmt.els.is_some() + && let Some(attr_span) = + is_rustc_must_match_exhaustively(cx, let_stmt.pat.hir_id) + { + cx.emit_span_lint( + RUSTC_MUST_MATCH_EXHAUSTIVELY, + let_stmt.span, + RustcMustMatchExhaustivelyNotExhaustive { + attr_span, + pat_span: let_stmt.pat.span, + message: "using `let else` only matches on one variant (try using `match`)", }, ); } diff --git a/tests/ui-fulldeps/internal-lints/must_match_exhaustively.rs b/tests/ui-fulldeps/internal-lints/must_match_exhaustively.rs index cc3dcebd11cdd..e3a77471a0fe5 100644 --- a/tests/ui-fulldeps/internal-lints/must_match_exhaustively.rs +++ b/tests/ui-fulldeps/internal-lints/must_match_exhaustively.rs @@ -43,6 +43,9 @@ fn foo(f: Foo) { if let Foo::A { .. } = f {} //~^ ERROR match is not exhaustive + + let Foo::A { .. } = f else { loop {} }; + //~^ ERROR match is not exhaustive } fn main() {} diff --git a/tests/ui-fulldeps/internal-lints/must_match_exhaustively.stderr b/tests/ui-fulldeps/internal-lints/must_match_exhaustively.stderr index e17cfcefc4093..a6ef63c5aba8c 100644 --- a/tests/ui-fulldeps/internal-lints/must_match_exhaustively.stderr +++ b/tests/ui-fulldeps/internal-lints/must_match_exhaustively.stderr @@ -61,11 +61,27 @@ LL | if let Foo::A { .. } = f {} | ^^^^^^^^^^^^^^^^^^^^^ | = help: explicitly list all variants of the enum in a `match` -note: using if let only matches on one variant (try using `match`) +note: using `if let` only matches on one variant (try using `match`) --> $DIR/must_match_exhaustively.rs:44:8 | LL | if let Foo::A { .. } = f {} | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: match is not exhaustive + --> $DIR/must_match_exhaustively.rs:47:5 + | +LL | #[rustc_must_match_exhaustively] + | -------------------------------- required because of this attribute +... +LL | let Foo::A { .. } = f else { loop {} }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: explicitly list all variants of the enum in a `match` +note: using `let else` only matches on one variant (try using `match`) + --> $DIR/must_match_exhaustively.rs:47:9 + | +LL | let Foo::A { .. } = f else { loop {} }; + | ^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors From 26a0fdcdcdaf41742a489026e1e540f74d7ecb82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 14 Apr 2026 10:59:42 +0200 Subject: [PATCH 11/11] fixup let-else on typing mode in the compiler --- compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 13 ++++++++++--- compiler/rustc_hir_typeck/src/opaque_types.rs | 16 ++++++++++++---- .../src/solve/assembly/mod.rs | 2 +- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index d3dcb65e71ee2..c863ac8e3e760 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -673,9 +673,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // being stalled on a coroutine. self.select_obligations_where_possible(|_| {}); - let ty::TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode() - else { - bug!(); + let defining_opaque_types_and_generators = match self.typing_mode() { + ty::TypingMode::Analysis { defining_opaque_types_and_generators } => { + defining_opaque_types_and_generators + } + ty::TypingMode::Coherence + | ty::TypingMode::Borrowck { .. } + | ty::TypingMode::PostBorrowckAnalysis { .. } + | ty::TypingMode::PostAnalysis => { + bug!() + } }; if defining_opaque_types_and_generators diff --git a/compiler/rustc_hir_typeck/src/opaque_types.rs b/compiler/rustc_hir_typeck/src/opaque_types.rs index 18c1bf39a7c13..b73bfabe92e60 100644 --- a/compiler/rustc_hir_typeck/src/opaque_types.rs +++ b/compiler/rustc_hir_typeck/src/opaque_types.rs @@ -1,8 +1,9 @@ use rustc_hir::def::DefKind; use rustc_infer::traits::ObligationCause; +use rustc_middle::bug; use rustc_middle::ty::{ self, DefiningScopeKind, DefinitionSiteHiddenType, OpaqueTypeKey, ProvisionalHiddenType, - TypeVisitableExt, TypingMode, + TypeVisitableExt, }; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::opaque_types::{ @@ -97,9 +98,16 @@ impl<'tcx> FnCtxt<'_, 'tcx> { debug!(?opaque_types); let tcx = self.tcx; - let TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode() - else { - unreachable!(); + let defining_opaque_types_and_generators = match self.typing_mode() { + ty::TypingMode::Analysis { defining_opaque_types_and_generators } => { + defining_opaque_types_and_generators + } + ty::TypingMode::Coherence + | ty::TypingMode::Borrowck { .. } + | ty::TypingMode::PostBorrowckAnalysis { .. } + | ty::TypingMode::PostAnalysis => { + bug!() + } }; for def_id in defining_opaque_types_and_generators { 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 8d855be720252..2e17885b4f44d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -442,7 +442,7 @@ where // normalizing the self type as well, since type variables are not uniquified. let goal = self.resolve_vars_if_possible(goal); - if let TypingMode::Coherence = self.typing_mode() + if self.typing_mode().is_coherence() && let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) { candidates.push(candidate);