Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 23 additions & 8 deletions compiler/rustc_span/src/hygiene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ use crate::symbol::{Symbol, kw, sym};
use crate::{DUMMY_SP, HashStableContext, Span, SpanDecoder, SpanEncoder, with_session_globals};

/// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks".
///
/// This can generally be thought of as the macro call stack for a given location in code.
/// Although, when a macro emits code from input parameters, that emitted code retains its
/// call-site SyntaxContext.
///
/// See https://rustc-dev-guide.rust-lang.org/macro-expansion.html for more explanation.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct SyntaxContext(u32);

Expand All @@ -61,7 +67,10 @@ pub type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency);

#[derive(Clone, Copy, Debug)]
struct SyntaxContextData {
/// The last macro expansion.
/// (Here we say the most deeply nested macro expansion is the "outermost" expansion.)
outer_expn: ExpnId,
/// Transparency of the last macro expansion
outer_transparency: Transparency,
parent: SyntaxContext,
/// This context, but with all transparent and semi-opaque expansions filtered away.
Expand Down Expand Up @@ -450,11 +459,13 @@ impl HygieneData {
self.syntax_context_data[ctxt.0 as usize].opaque_and_semiopaque
}

/// See [`SyntaxContextData::outer_expn`]
#[inline]
fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId {
self.syntax_context_data[ctxt.0 as usize].outer_expn
}

/// The last macro expansion and its Transparency
#[inline]
fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) {
let data = &self.syntax_context_data[ctxt.0 as usize];
Expand Down Expand Up @@ -900,6 +911,7 @@ impl SyntaxContext {
HygieneData::with(|data| data.normalize_to_macro_rules(self))
}

/// See [`SyntaxContextData::outer_expn`]
#[inline]
pub fn outer_expn(self) -> ExpnId {
HygieneData::with(|data| data.outer_expn(self))
Expand All @@ -912,6 +924,7 @@ impl SyntaxContext {
HygieneData::with(|data| data.expn_data(data.outer_expn(self)).clone())
}

/// See [`HygieneData::outer_mark`]
#[inline]
fn outer_mark(self) -> (ExpnId, Transparency) {
HygieneData::with(|data| data.outer_mark(self))
Expand Down Expand Up @@ -986,15 +999,17 @@ pub struct ExpnData {
pub kind: ExpnKind,
/// The expansion that produced this expansion.
pub parent: ExpnId,
/// The location of the actual macro invocation or syntax sugar , e.g.
/// `let x = foo!();` or `if let Some(y) = x {}`
/// The span of the macro call which produced this expansion.
///
/// This span will typically have a different `ExpnData` and `call_site`.
/// This recursively traces back through any macro calls which expanded into further
/// macro calls, until the "source call-site" is reached at the root SyntaxContext.
/// For example, if `food!()` expands to `fruit!()` which then expands to `grape`,
/// then the call-site of `grape` is `fruit!()` and the call-site of `fruit!()`
/// is `food!()`.
///
/// This may recursively refer to other macro invocations, e.g., if
/// `foo!()` invoked `bar!()` internally, and there was an
/// expression inside `bar!`; the call_site of the expression in
/// the expansion would point to the `bar!` invocation; that
/// call_site span would have its own ExpnData, with the call_site
/// pointing to the `foo!` invocation.
/// For a desugaring expansion, this is the span of the expression or node that was
/// desugared.
pub call_site: Span,
/// Used to force two `ExpnData`s to have different `Fingerprint`s.
/// Due to macro expansion, it's possible to end up with two `ExpnId`s
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_span/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -710,8 +710,8 @@ impl Span {
if !ctxt.is_root() { ctxt.outer_expn_data().call_site.source_callsite() } else { self }
}

/// The `Span` for the tokens in the previous macro expansion from which `self` was generated,
/// if any.
/// Returns the call-site span of the last macro expansion which produced this `Span`.
/// (see [`ExpnData::call_site`]). Returns `None` if this is not an expansion.
pub fn parent_callsite(self) -> Option<Span> {
let ctxt = self.ctxt();
(!ctxt.is_root()).then(|| ctxt.outer_expn_data().call_site)
Expand Down
Loading