Skip to content

Commit 2f977ce

Browse files
committed
Create two methods to fix find_oldest_ancestor_in_same_ctxt
Signed-off-by: xizheyin <[email protected]>
1 parent 460259d commit 2f977ce

File tree

4 files changed

+57
-41
lines changed

4 files changed

+57
-41
lines changed

compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
341341
}
342342
}
343343
} else if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
344-
let sp = info.span.find_oldest_ancestor_in_same_ctxt();
344+
let sp = info.span.find_ancestor_not_from_macro().unwrap_or(info.span);
345345
if info.tail_result_is_ignored {
346346
// #85581: If the first mutable borrow's scope contains
347347
// the second borrow, this suggestion isn't helpful.

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,7 +1393,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13931393
.macro_backtrace()
13941394
.any(|x| matches!(x.kind, ExpnKind::Macro(MacroKind::Attr | MacroKind::Derive, ..)))
13951395
{
1396-
let span = expr.span.find_oldest_ancestor_in_same_ctxt();
1396+
let span = expr
1397+
.span
1398+
.find_ancestor_not_from_extern_macro(&self.tcx.sess.source_map())
1399+
.unwrap_or(expr.span);
13971400

13981401
let mut sugg = if self.precedence(expr) >= ExprPrecedence::Unambiguous {
13991402
vec![(span.shrink_to_hi(), ".into()".to_owned())]
@@ -2060,7 +2063,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20602063
None => sugg.to_string(),
20612064
};
20622065

2063-
let span = expr.span.find_oldest_ancestor_in_same_ctxt();
2066+
let span = expr
2067+
.span
2068+
.find_ancestor_not_from_extern_macro(&self.tcx.sess.source_map())
2069+
.unwrap_or(expr.span);
20642070
err.span_suggestion_verbose(span.shrink_to_hi(), msg, sugg, Applicability::HasPlaceholders);
20652071
true
20662072
}

compiler/rustc_lint/src/unused.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
185185
let mut op_warned = false;
186186

187187
if let Some(must_use_op) = must_use_op {
188-
let span = expr.span.find_oldest_ancestor_in_same_ctxt();
188+
let span = expr.span.find_ancestor_not_from_macro().unwrap_or(expr.span);
189189
cx.emit_span_lint(
190190
UNUSED_MUST_USE,
191191
expr.span,
@@ -511,7 +511,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
511511
);
512512
}
513513
MustUsePath::Def(span, def_id, reason) => {
514-
let span = span.find_oldest_ancestor_in_same_ctxt();
514+
let span = span.find_ancestor_not_from_macro().unwrap_or(*span);
515515
cx.emit_span_lint(
516516
UNUSED_MUST_USE,
517517
span,

compiler/rustc_span/src/lib.rs

Lines changed: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -715,12 +715,17 @@ impl Span {
715715
(!ctxt.is_root()).then(|| ctxt.outer_expn_data().call_site)
716716
}
717717

718-
/// Walk down the expansion ancestors to find a span that's contained within `outer`.
718+
/// Find the first ancestor span that's contained within `outer`.
719719
///
720-
/// The span returned by this method may have a different [`SyntaxContext`] as `outer`.
720+
/// This method traverses the macro expansion ancestors until it finds the first span
721+
/// that's contained within `outer`.
722+
///
723+
/// The span returned by this method may have a different [`SyntaxContext`] than `outer`.
721724
/// If you need to extend the span, use [`find_ancestor_inside_same_ctxt`] instead,
722725
/// because joining spans with different syntax contexts can create unexpected results.
723726
///
727+
/// This is used to find the span of the macro call when a parent expr span, i.e. `outer`, is known.
728+
///
724729
/// [`find_ancestor_inside_same_ctxt`]: Self::find_ancestor_inside_same_ctxt
725730
pub fn find_ancestor_inside(mut self, outer: Span) -> Option<Span> {
726731
while !outer.contains(self) {
@@ -729,8 +734,10 @@ impl Span {
729734
Some(self)
730735
}
731736

732-
/// Walk down the expansion ancestors to find a span with the same [`SyntaxContext`] as
733-
/// `other`.
737+
/// Find the first ancestor span with the same [`SyntaxContext`] as `other`.
738+
///
739+
/// This method traverses the macro expansion ancestors until it finds a span
740+
/// that has the same [`SyntaxContext`] as `other`.
734741
///
735742
/// Like [`find_ancestor_inside_same_ctxt`], but specifically for when spans might not
736743
/// overlap. Take care when using this, and prefer [`find_ancestor_inside`] or
@@ -746,9 +753,12 @@ impl Span {
746753
Some(self)
747754
}
748755

749-
/// Walk down the expansion ancestors to find a span that's contained within `outer` and
756+
/// Find the first ancestor span that's contained within `outer` and
750757
/// has the same [`SyntaxContext`] as `outer`.
751758
///
759+
/// This method traverses the macro expansion ancestors until it finds a span
760+
/// that is both contained within `outer` and has the same [`SyntaxContext`] as `outer`.
761+
///
752762
/// This method is the combination of [`find_ancestor_inside`] and
753763
/// [`find_ancestor_in_same_ctxt`] and should be preferred when extending the returned span.
754764
/// If you do not need to modify the span, use [`find_ancestor_inside`] instead.
@@ -762,43 +772,43 @@ impl Span {
762772
Some(self)
763773
}
764774

765-
/// Recursively walk down the expansion ancestors to find the oldest ancestor span with the same
766-
/// [`SyntaxContext`] the initial span.
775+
/// Find the first ancestor span that does not come from an external macro.
767776
///
768-
/// This method is suitable for peeling through *local* macro expansions to find the "innermost"
769-
/// span that is still local and shares the same [`SyntaxContext`]. For example, given
777+
/// This method traverses the macro expansion ancestors until it finds a span
778+
/// that is either from user-written code or from a local macro (defined in the current crate).
770779
///
771-
/// ```ignore (illustrative example, contains type error)
772-
/// macro_rules! outer {
773-
/// ($x: expr) => {
774-
/// inner!($x)
775-
/// }
776-
/// }
780+
/// External macros are those defined in dependencies or the standard library.
781+
/// This method is useful for reporting errors in user-controllable code and avoiding
782+
/// diagnostics inside external macros.
777783
///
778-
/// macro_rules! inner {
779-
/// ($x: expr) => {
780-
/// format!("error: {}", $x)
781-
/// //~^ ERROR mismatched types
782-
/// }
783-
/// }
784+
/// # See also
784785
///
785-
/// fn bar(x: &str) -> Result<(), Box<dyn std::error::Error>> {
786-
/// Err(outer!(x))
787-
/// }
788-
/// ```
786+
/// - [`find_ancestor_not_from_macro`]: Finds ancestors not from any macro (local or external)
787+
/// - [`Span::in_external_macro`]: Checks if a span comes from an external macro
788+
pub fn find_ancestor_not_from_extern_macro(mut self, sm: &SourceMap) -> Option<Span> {
789+
while self.in_external_macro(sm) {
790+
self = self.parent_callsite()?;
791+
}
792+
Some(self)
793+
}
794+
795+
/// Find the first ancestor span that does not come from any macro expansion.
789796
///
790-
/// if provided the initial span of `outer!(x)` inside `bar`, this method will recurse
791-
/// the parent callsites until we reach `format!("error: {}", $x)`, at which point it is the
792-
/// oldest ancestor span that is both still local and shares the same [`SyntaxContext`] as the
793-
/// initial span.
794-
pub fn find_oldest_ancestor_in_same_ctxt(self) -> Span {
795-
let mut cur = self;
796-
while cur.eq_ctxt(self)
797-
&& let Some(parent_callsite) = cur.parent_callsite()
798-
{
799-
cur = parent_callsite;
797+
/// This method traverses the macro expansion ancestors until it finds a span
798+
/// that originates from user-written code rather than any macro-generated code.
799+
///
800+
/// This method is useful for reporting errors at the exact location users wrote code
801+
/// and providing suggestions at directly editable locations.
802+
///
803+
/// # See also
804+
///
805+
/// - [`find_ancestor_not_from_extern_macro`]: Only filters out external macros, keeps local ones
806+
/// - [`Span::from_expansion`]: Checks if a span comes from any macro expansion
807+
pub fn find_ancestor_not_from_macro(mut self) -> Option<Span> {
808+
while self.from_expansion() {
809+
self = self.parent_callsite()?;
800810
}
801-
cur
811+
Some(self)
802812
}
803813

804814
/// Edition of the crate from which this span came.

0 commit comments

Comments
 (0)