From 0b953496882922f1bd408b313f03047bfc61b588 Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Tue, 17 Mar 2026 14:19:12 +0300 Subject: [PATCH] Select proper span for delegation, update span of child path segment if needed --- compiler/rustc_ast_lowering/src/delegation.rs | 44 ++++++++++++++----- compiler/rustc_ast_lowering/src/item.rs | 6 +-- .../delegation/impl-reuse-negative-traits.rs | 2 +- .../impl-reuse-negative-traits.stderr | 6 +-- 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 050e72505abb8..6deecaeeee5cc 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -154,8 +154,26 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, delegation: &Delegation, item_id: NodeId, + item_span: Span, ) -> DelegationResults<'hir> { - let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span); + let last_seg_span = self.lower_span(delegation.path.segments.last().unwrap().ident.span); + let item_span = self.lower_span(item_span); + + // Check if the span of the last segment is contained in item span. The span of last segment + // may refer to completely different entity, for example when we do a glob reuse we + // generate segments (in `rustc_expand::expand::build_single_delegations`), + // and during `rustc_resolve::macros::glob_delegation_suffixes` we generate + // suffixes, where identifiers that are used in generated segment + // use spans of the original functions from trait, + // thus those spans can point either to local or external + // trait functions. This `span` is also used for diagnostics purposes, so we want it to point + // to delegation, not to the random trait function, so we perform this check here. + // We could have added similar check in `rustc_resolve::macros::glob_delegation_suffixes` + // (i.e. create ident with span related to ast path of delegation, not the original trait item), + // or in `rustc_expand::expand::build_single_delegations`, + // however it will break `impl-reuse-pass` test and checking span here seems to be good solution, + // as bad spans may come from different places in future. + let span = if item_span.contains(last_seg_span) { last_seg_span } else { item_span }; // Delegation can be unresolved in illegal places such as function bodies in extern blocks (see #151356) let ids = if let Some(delegation_info) = @@ -651,7 +669,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // FIXME(fn_delegation): proper support for parent generics propagation // in method call scenario. - let segment = self.process_segment(item_id, span, &segment, &mut generics.child, false); + let segment = self.process_segment(item_id, span, &segment, &mut generics.child, true); let segment = self.arena.alloc(segment); self.arena.alloc(hir::Expr { @@ -677,14 +695,14 @@ impl<'hir> LoweringContext<'_, 'hir> { new_path.segments = self.arena.alloc_from_iter( new_path.segments.iter().enumerate().map(|(idx, segment)| { - let mut process_segment = |result, add_lifetimes| { - self.process_segment(item_id, span, segment, result, add_lifetimes) + let mut process_segment = |result, is_child| { + self.process_segment(item_id, span, segment, result, is_child) }; if idx + 2 == len { - process_segment(&mut generics.parent, true) + process_segment(&mut generics.parent, false) } else if idx + 1 == len { - process_segment(&mut generics.child, false) + process_segment(&mut generics.child, true) } else { segment.clone() } @@ -695,7 +713,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } hir::QPath::TypeRelative(ty, segment) => { let segment = - self.process_segment(item_id, span, segment, &mut generics.child, false); + self.process_segment(item_id, span, segment, &mut generics.child, true); hir::QPath::TypeRelative(ty, self.arena.alloc(segment)) } @@ -723,17 +741,17 @@ impl<'hir> LoweringContext<'_, 'hir> { span: Span, segment: &hir::PathSegment<'hir>, result: &mut GenericsGenerationResult<'hir>, - add_lifetimes: bool, + is_child_segment: bool, ) -> hir::PathSegment<'hir> { let details = result.generics.args_propagation_details(); // The first condition is needed when there is SelfAndUserSpecified case, // we don't want to propagate generics params in this situation. - let segment = if details.should_propagate + let mut segment = if details.should_propagate && let Some(args) = result .generics .into_hir_generics(self, item_id, span) - .into_generic_args(self, add_lifetimes, span) + .into_generic_args(self, !is_child_segment, span) { hir::PathSegment { args: Some(args), ..segment.clone() } } else { @@ -744,6 +762,12 @@ impl<'hir> LoweringContext<'_, 'hir> { result.args_segment_id = Some(segment.hir_id); } + // Update segment ident span if it is not contained in delegation span, see comment + // in `lower_delegation` function in this file. + if is_child_segment && !span.contains(segment.ident.span) { + segment.ident.span = span; + } + segment } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index e2ac38caf2950..eb19f50efb2e6 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -579,7 +579,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ItemKind::Macro(ident, macro_def, macro_kinds) } ItemKind::Delegation(box delegation) => { - let delegation_results = self.lower_delegation(delegation, id); + let delegation_results = self.lower_delegation(delegation, id, span); hir::ItemKind::Fn { sig: delegation_results.sig, ident: delegation_results.ident, @@ -1079,7 +1079,7 @@ impl<'hir> LoweringContext<'_, 'hir> { (*ident, generics, kind, ty.is_some()) } AssocItemKind::Delegation(box delegation) => { - let delegation_results = self.lower_delegation(delegation, i.id); + let delegation_results = self.lower_delegation(delegation, i.id, i.span); let item_kind = hir::TraitItemKind::Fn( delegation_results.sig, hir::TraitFn::Provided(delegation_results.body_id), @@ -1272,7 +1272,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } AssocItemKind::Delegation(box delegation) => { - let delegation_results = self.lower_delegation(delegation, i.id); + let delegation_results = self.lower_delegation(delegation, i.id, i.span); ( delegation.ident, ( diff --git a/tests/ui/delegation/impl-reuse-negative-traits.rs b/tests/ui/delegation/impl-reuse-negative-traits.rs index 7bcbc82f03db8..d234d92f98c03 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 [E0749] 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