Skip to content

Commit a237641

Browse files
committed
Auto merge of #68407 - eddyb:iter-macro-backtrace, r=petrochenkov
rustc_span: return an impl Iterator instead of a Vec from macro_backtrace. Having `Span::macro_backtrace` produce an `impl Iterator<Item = ExpnData>` allows #67359 to use it instead of rolling its own similar functionality. The move from `MacroBacktrace` to `ExpnData` (which the first two commits are prerequisites for) both eliminates unnecessary allocations, and is strictly more flexible (exposes more information). r? @petrochenkov
2 parents 698fcd3 + 6980f82 commit a237641

File tree

16 files changed

+75
-86
lines changed

16 files changed

+75
-86
lines changed

src/librustc_errors/emitter.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use crate::{
2121

2222
use rustc_data_structures::fx::FxHashMap;
2323
use rustc_data_structures::sync::Lrc;
24+
use rustc_span::hygiene::{ExpnKind, MacroKind};
2425
use std::borrow::Cow;
2526
use std::cmp::{max, min, Reverse};
2627
use std::io;
@@ -342,19 +343,20 @@ pub trait Emitter {
342343
if call_sp != *sp && !always_backtrace {
343344
before_after.push((*sp, call_sp));
344345
}
345-
let backtrace_len = sp.macro_backtrace().len();
346-
for (i, trace) in sp.macro_backtrace().iter().rev().enumerate() {
346+
let macro_backtrace: Vec<_> = sp.macro_backtrace().collect();
347+
let backtrace_len = macro_backtrace.len();
348+
for (i, trace) in macro_backtrace.iter().rev().enumerate() {
347349
// Only show macro locations that are local
348350
// and display them like a span_note
349-
if trace.def_site_span.is_dummy() {
351+
if trace.def_site.is_dummy() {
350352
continue;
351353
}
352354
if always_backtrace {
353355
new_labels.push((
354-
trace.def_site_span,
356+
trace.def_site,
355357
format!(
356358
"in this expansion of `{}`{}",
357-
trace.macro_decl_name,
359+
trace.kind.descr(),
358360
if backtrace_len > 2 {
359361
// if backtrace_len == 1 it'll be pointed
360362
// at by "in this macro invocation"
@@ -366,9 +368,8 @@ pub trait Emitter {
366368
));
367369
}
368370
// Check to make sure we're not in any <*macros>
369-
if !sm.span_to_filename(trace.def_site_span).is_macros()
370-
&& !trace.macro_decl_name.starts_with("desugaring of ")
371-
&& !trace.macro_decl_name.starts_with("#[")
371+
if !sm.span_to_filename(trace.def_site).is_macros()
372+
&& matches!(trace.kind, ExpnKind::Macro(MacroKind::Bang, _))
372373
|| always_backtrace
373374
{
374375
new_labels.push((
@@ -398,8 +399,7 @@ pub trait Emitter {
398399
continue;
399400
}
400401
if sm.span_to_filename(sp_label.span.clone()).is_macros() && !always_backtrace {
401-
let v = sp_label.span.macro_backtrace();
402-
if let Some(use_site) = v.last() {
402+
if let Some(use_site) = sp_label.span.macro_backtrace().last() {
403403
before_after.push((sp_label.span.clone(), use_site.call_site.clone()));
404404
}
405405
}

src/librustc_errors/json.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ use crate::{Applicability, DiagnosticId};
1717
use crate::{CodeSuggestion, SubDiagnostic};
1818

1919
use rustc_data_structures::sync::Lrc;
20-
use rustc_span::{MacroBacktrace, MultiSpan, Span, SpanLabel};
20+
use rustc_span::hygiene::ExpnData;
21+
use rustc_span::{MultiSpan, Span, SpanLabel};
2122
use std::io::{self, Write};
2223
use std::path::Path;
2324
use std::sync::{Arc, Mutex};
@@ -308,7 +309,7 @@ impl DiagnosticSpan {
308309
// backtrace ourselves, but the `macro_backtrace` helper makes
309310
// some decision, such as dropping some frames, and I don't
310311
// want to duplicate that logic here.
311-
let backtrace = span.macro_backtrace().into_iter();
312+
let backtrace = span.macro_backtrace();
312313
DiagnosticSpan::from_span_full(span, is_primary, label, suggestion, backtrace, je)
313314
}
314315

@@ -317,18 +318,18 @@ impl DiagnosticSpan {
317318
is_primary: bool,
318319
label: Option<String>,
319320
suggestion: Option<(&String, Applicability)>,
320-
mut backtrace: vec::IntoIter<MacroBacktrace>,
321+
mut backtrace: impl Iterator<Item = ExpnData>,
321322
je: &JsonEmitter,
322323
) -> DiagnosticSpan {
323324
let start = je.sm.lookup_char_pos(span.lo());
324325
let end = je.sm.lookup_char_pos(span.hi());
325326
let backtrace_step = backtrace.next().map(|bt| {
326327
let call_site = Self::from_span_full(bt.call_site, false, None, None, backtrace, je);
327328
let def_site_span =
328-
Self::from_span_full(bt.def_site_span, false, None, None, vec![].into_iter(), je);
329+
Self::from_span_full(bt.def_site, false, None, None, vec![].into_iter(), je);
329330
Box::new(DiagnosticSpanMacroExpansion {
330331
span: call_site,
331-
macro_decl_name: bt.macro_decl_name,
332+
macro_decl_name: bt.kind.descr(),
332333
def_site_span,
333334
})
334335
});

src/librustc_expand/expand.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -596,10 +596,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
596596
let suggested_limit = self.cx.ecfg.recursion_limit * 2;
597597
let mut err = self.cx.struct_span_err(
598598
expn_data.call_site,
599-
&format!(
600-
"recursion limit reached while expanding the macro `{}`",
601-
expn_data.kind.descr()
602-
),
599+
&format!("recursion limit reached while expanding `{}`", expn_data.kind.descr()),
603600
);
604601
err.help(&format!(
605602
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",

src/librustc_lint/internal.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_data_structures::fx::FxHashMap;
66
use rustc_errors::Applicability;
77
use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, Ty, TyKind};
88
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
9+
use rustc_span::hygiene::{ExpnKind, MacroKind};
910
use rustc_span::symbol::{sym, Symbol};
1011
use syntax::ast::{Ident, Item, ItemKind};
1112

@@ -226,8 +227,9 @@ impl EarlyLintPass for LintPassImpl {
226227
if last.ident.name == sym::LintPass {
227228
let expn_data = lint_pass.path.span.ctxt().outer_expn_data();
228229
let call_site = expn_data.call_site;
229-
if expn_data.kind.descr() != sym::impl_lint_pass
230-
&& call_site.ctxt().outer_expn_data().kind.descr() != sym::declare_lint_pass
230+
if expn_data.kind != ExpnKind::Macro(MacroKind::Bang, sym::impl_lint_pass)
231+
&& call_site.ctxt().outer_expn_data().kind
232+
!= ExpnKind::Macro(MacroKind::Bang, sym::declare_lint_pass)
231233
{
232234
cx.struct_span_lint(
233235
LINT_PASS_IMPL_WITHOUT_MACRO,

src/librustc_save_analysis/lib.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -776,12 +776,19 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
776776
let callsite_span = self.span_from_span(callsite);
777777
let callee = span.source_callee()?;
778778

779-
// Ignore attribute macros, their spans are usually mangled
780-
if let ExpnKind::Macro(MacroKind::Attr, _) | ExpnKind::Macro(MacroKind::Derive, _) =
781-
callee.kind
782-
{
783-
return None;
784-
}
779+
let mac_name = match callee.kind {
780+
ExpnKind::Macro(mac_kind, name) => match mac_kind {
781+
MacroKind::Bang => name,
782+
783+
// Ignore attribute macros, their spans are usually mangled
784+
// FIXME(eddyb) is this really the case anymore?
785+
MacroKind::Attr | MacroKind::Derive => return None,
786+
},
787+
788+
// These are not macros.
789+
// FIXME(eddyb) maybe there is a way to handle them usefully?
790+
ExpnKind::Root | ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => return None,
791+
};
785792

786793
// If the callee is an imported macro from an external crate, need to get
787794
// the source span and name from the session, as their spans are localized
@@ -799,7 +806,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
799806
let callee_span = self.span_from_span(callee.def_site);
800807
Some(MacroRef {
801808
span: callsite_span,
802-
qualname: callee.kind.descr().to_string(), // FIXME: generate the real qualname
809+
qualname: mac_name.to_string(), // FIXME: generate the real qualname
803810
callee_span,
804811
})
805812
}

src/librustc_span/hygiene.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,9 @@ impl ExpnId {
140140
loop {
141141
let expn_data = self.expn_data();
142142
// Stop going up the backtrace once include! is encountered
143-
if expn_data.is_root() || expn_data.kind.descr() == sym::include {
143+
if expn_data.is_root()
144+
|| expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include)
145+
{
144146
break;
145147
}
146148
self = expn_data.call_site.ctxt().outer_expn();
@@ -717,7 +719,7 @@ impl ExpnData {
717719
}
718720

719721
/// Expansion kind.
720-
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable_Generic)]
722+
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable, HashStable_Generic)]
721723
pub enum ExpnKind {
722724
/// No expansion, aka root expansion. Only `ExpnId::root()` has this kind.
723725
Root,
@@ -730,12 +732,16 @@ pub enum ExpnKind {
730732
}
731733

732734
impl ExpnKind {
733-
pub fn descr(&self) -> Symbol {
735+
pub fn descr(&self) -> String {
734736
match *self {
735-
ExpnKind::Root => kw::PathRoot,
736-
ExpnKind::Macro(_, descr) => descr,
737-
ExpnKind::AstPass(kind) => Symbol::intern(kind.descr()),
738-
ExpnKind::Desugaring(kind) => Symbol::intern(kind.descr()),
737+
ExpnKind::Root => kw::PathRoot.to_string(),
738+
ExpnKind::Macro(macro_kind, name) => match macro_kind {
739+
MacroKind::Bang => format!("{}!", name),
740+
MacroKind::Attr => format!("#[{}]", name),
741+
MacroKind::Derive => format!("#[derive({})]", name),
742+
},
743+
ExpnKind::AstPass(kind) => kind.descr().to_string(),
744+
ExpnKind::Desugaring(kind) => format!("desugaring of {}", kind.descr()),
739745
}
740746
}
741747
}

src/librustc_span/lib.rs

+18-41
Original file line numberDiff line numberDiff line change
@@ -445,37 +445,26 @@ impl Span {
445445
self.ctxt().outer_expn_data().allow_internal_unsafe
446446
}
447447

448-
pub fn macro_backtrace(mut self) -> Vec<MacroBacktrace> {
448+
pub fn macro_backtrace(mut self) -> impl Iterator<Item = ExpnData> {
449449
let mut prev_span = DUMMY_SP;
450-
let mut result = vec![];
451-
loop {
452-
let expn_data = self.ctxt().outer_expn_data();
453-
if expn_data.is_root() {
454-
break;
455-
}
456-
// Don't print recursive invocations.
457-
if !expn_data.call_site.source_equal(&prev_span) {
458-
let (pre, post) = match expn_data.kind {
459-
ExpnKind::Root => break,
460-
ExpnKind::Desugaring(..) => ("desugaring of ", ""),
461-
ExpnKind::AstPass(..) => ("", ""),
462-
ExpnKind::Macro(macro_kind, _) => match macro_kind {
463-
MacroKind::Bang => ("", "!"),
464-
MacroKind::Attr => ("#[", "]"),
465-
MacroKind::Derive => ("#[derive(", ")]"),
466-
},
467-
};
468-
result.push(MacroBacktrace {
469-
call_site: expn_data.call_site,
470-
macro_decl_name: format!("{}{}{}", pre, expn_data.kind.descr(), post),
471-
def_site_span: expn_data.def_site,
472-
});
473-
}
450+
std::iter::from_fn(move || {
451+
loop {
452+
let expn_data = self.ctxt().outer_expn_data();
453+
if expn_data.is_root() {
454+
return None;
455+
}
474456

475-
prev_span = self;
476-
self = expn_data.call_site;
477-
}
478-
result
457+
let is_recursive = expn_data.call_site.source_equal(&prev_span);
458+
459+
prev_span = self;
460+
self = expn_data.call_site;
461+
462+
// Don't print recursive invocations.
463+
if !is_recursive {
464+
return Some(expn_data);
465+
}
466+
}
467+
})
479468
}
480469

481470
/// Returns a `Span` that would enclose both `self` and `end`.
@@ -1511,18 +1500,6 @@ pub struct FileLines {
15111500
pub static SPAN_DEBUG: AtomicRef<fn(Span, &mut fmt::Formatter<'_>) -> fmt::Result> =
15121501
AtomicRef::new(&(default_span_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
15131502

1514-
#[derive(Debug)]
1515-
pub struct MacroBacktrace {
1516-
/// span where macro was applied to generate this code
1517-
pub call_site: Span,
1518-
1519-
/// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]")
1520-
pub macro_decl_name: String,
1521-
1522-
/// span where macro was defined (possibly dummy)
1523-
pub def_site_span: Span,
1524-
}
1525-
15261503
// _____________________________________________________________________________
15271504
// SpanLinesError, SpanSnippetError, DistinctSources, MalformedSourceMapPositions
15281505
//

src/librustc_span/source_map.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -947,8 +947,7 @@ impl SourceMap {
947947
}
948948
pub fn call_span_if_macro(&self, sp: Span) -> Span {
949949
if self.span_to_filename(sp.clone()).is_macros() {
950-
let v = sp.macro_backtrace();
951-
if let Some(use_site) = v.last() {
950+
if let Some(use_site) = sp.macro_backtrace().last() {
952951
return use_site.call_site;
953952
}
954953
}

src/test/ui/did_you_mean/recursion_limit_macro.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: recursion limit reached while expanding the macro `recurse`
1+
error: recursion limit reached while expanding `recurse!`
22
--> $DIR/recursion_limit_macro.rs:10:31
33
|
44
LL | ($t:tt $($tail:tt)*) => { recurse!($($tail)*) };

src/test/ui/infinite/infinite-macro-expansion.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
macro_rules! recursive {
2-
() => (recursive!()) //~ ERROR recursion limit reached while expanding the macro `recursive`
2+
() => (recursive!()) //~ ERROR recursion limit reached while expanding `recursive!`
33
}
44

55
fn main() {

src/test/ui/infinite/infinite-macro-expansion.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: recursion limit reached while expanding the macro `recursive`
1+
error: recursion limit reached while expanding `recursive!`
22
--> $DIR/infinite-macro-expansion.rs:2:12
33
|
44
LL | () => (recursive!())

src/test/ui/issues/issue-16098.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ macro_rules! prob1 {
44
};
55
($n:expr) => {
66
if ($n % 3 == 0) || ($n % 5 == 0) {
7-
$n + prob1!($n - 1); //~ ERROR recursion limit reached while expanding the macro `prob1`
7+
$n + prob1!($n - 1); //~ ERROR recursion limit reached while expanding `prob1!`
88
} else {
99
prob1!($n - 1);
1010
}

src/test/ui/issues/issue-16098.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: recursion limit reached while expanding the macro `prob1`
1+
error: recursion limit reached while expanding `prob1!`
22
--> $DIR/issue-16098.rs:7:18
33
|
44
LL | $n + prob1!($n - 1);

src/test/ui/macros/trace_faulty_macros.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ LL | my_faulty_macro!();
2020
= note: to `my_faulty_macro ! (bcd) ;`
2121
= note: expanding `my_faulty_macro! { bcd }`
2222

23-
error: recursion limit reached while expanding the macro `my_recursive_macro`
23+
error: recursion limit reached while expanding `my_recursive_macro!`
2424
--> $DIR/trace_faulty_macros.rs:22:9
2525
|
2626
LL | my_recursive_macro!();

src/tools/clippy

Submodule clippy updated 45 files

0 commit comments

Comments
 (0)