Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustc_span: Optimize syntax context comparisons #119531

Merged
merged 1 commit into from
Jan 6, 2024
Merged
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
2 changes: 1 addition & 1 deletion compiler/rustc_expand/src/mbe/quoted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ pub(super) fn parse(
// `SyntaxContext::root()` from a foreign crate will
// have the edition of that crate (which we manually
// retrieve via the `edition` parameter).
if span.ctxt().is_root() {
if !span.from_expansion() {
edition
} else {
span.edition()
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_lint/src/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,9 @@ declare_lint_pass!(SpanUseEqCtxt => [SPAN_USE_EQ_CTXT]);

impl<'tcx> LateLintPass<'tcx> for SpanUseEqCtxt {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
if let ExprKind::Binary(BinOp { node: BinOpKind::Eq, .. }, lhs, rhs) = expr.kind {
if let ExprKind::Binary(BinOp { node: BinOpKind::Eq | BinOpKind::Ne, .. }, lhs, rhs) =
expr.kind
{
if is_span_ctxt_call(cx, lhs) && is_span_ctxt_call(cx, rhs) {
cx.emit_spanned_lint(SPAN_USE_EQ_CTXT, expr.span, SpanUseEqCtxtDiag);
}
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_lint/src/non_fmt_panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,11 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
let mut arg_span = arg.span;
let mut arg_macro = None;
while !span.contains(arg_span) {
let expn = arg_span.ctxt().outer_expn_data();
if expn.is_root() {
let ctxt = arg_span.ctxt();
if ctxt.is_root() {
break;
}
let expn = ctxt.outer_expn_data();
arg_macro = expn.macro_def_id;
arg_span = expn.call_site;
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_passes/src/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1630,7 +1630,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
let from_macro = non_shorthands
.iter()
.find(|(_, pat_span, ident_span)| {
pat_span.ctxt() != ident_span.ctxt() && pat_span.from_expansion()
!pat_span.eq_ctxt(*ident_span) && pat_span.from_expansion()
})
.map(|(_, pat_span, _)| *pat_span);
let non_shorthands = non_shorthands
Expand Down
10 changes: 6 additions & 4 deletions compiler/rustc_span/src/hygiene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,11 +295,13 @@ impl ExpnId {
pub fn expansion_cause(mut self) -> Option<Span> {
let mut last_macro = None;
loop {
// Fast path to avoid locking.
if self == ExpnId::root() {
break;
}
let expn_data = self.expn_data();
// Stop going up the backtrace once include! is encountered
if expn_data.is_root()
|| expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include)
{
if expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include) {
break;
}
self = expn_data.call_site.ctxt().outer_expn();
Expand Down Expand Up @@ -433,7 +435,7 @@ impl HygieneData {

fn marks(&self, mut ctxt: SyntaxContext) -> Vec<(ExpnId, Transparency)> {
let mut marks = Vec::new();
while ctxt != SyntaxContext::root() {
while !ctxt.is_root() {
debug!("marks: getting parent of {:?}", ctxt);
marks.push(self.outer_mark(ctxt));
ctxt = self.parent_ctxt(ctxt);
Expand Down
36 changes: 16 additions & 20 deletions compiler/rustc_span/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,10 +541,6 @@ impl Span {
self.data().with_hi(hi)
}
#[inline]
pub fn eq_ctxt(self, other: Span) -> bool {
self.data_untracked().ctxt == other.data_untracked().ctxt
}
#[inline]
pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
self.data_untracked().with_ctxt(ctxt)
}
Expand All @@ -565,7 +561,7 @@ impl Span {
/// Returns `true` if this span comes from any kind of macro, desugaring or inlining.
#[inline]
pub fn from_expansion(self) -> bool {
self.ctxt() != SyntaxContext::root()
!self.ctxt().is_root()
}

/// Returns `true` if `span` originates in a macro's expansion where debuginfo should be
Expand Down Expand Up @@ -654,15 +650,15 @@ impl Span {
/// Returns the source span -- this is either the supplied span, or the span for
/// the macro callsite that expanded to it.
pub fn source_callsite(self) -> Span {
let expn_data = self.ctxt().outer_expn_data();
if !expn_data.is_root() { expn_data.call_site.source_callsite() } else { self }
let ctxt = self.ctxt();
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.
pub fn parent_callsite(self) -> Option<Span> {
let expn_data = self.ctxt().outer_expn_data();
if !expn_data.is_root() { Some(expn_data.call_site) } else { None }
let ctxt = self.ctxt();
(!ctxt.is_root()).then(|| ctxt.outer_expn_data().call_site)
}

/// Walk down the expansion ancestors to find a span that's contained within `outer`.
Expand Down Expand Up @@ -747,15 +743,14 @@ impl Span {
/// else returns the `ExpnData` for the macro definition
/// corresponding to the source callsite.
pub fn source_callee(self) -> Option<ExpnData> {
let expn_data = self.ctxt().outer_expn_data();

// Create an iterator of call site expansions
iter::successors(Some(expn_data), |expn_data| {
Some(expn_data.call_site.ctxt().outer_expn_data())
})
// Find the last expansion which is not root
.take_while(|expn_data| !expn_data.is_root())
.last()
let mut ctxt = self.ctxt();
let mut opt_expn_data = None;
while !ctxt.is_root() {
let expn_data = ctxt.outer_expn_data();
ctxt = expn_data.call_site.ctxt();
opt_expn_data = Some(expn_data);
}
opt_expn_data
}

/// Checks if a span is "internal" to a macro in which `#[unstable]`
Expand Down Expand Up @@ -796,11 +791,12 @@ impl Span {
let mut prev_span = DUMMY_SP;
iter::from_fn(move || {
loop {
let expn_data = self.ctxt().outer_expn_data();
if expn_data.is_root() {
let ctxt = self.ctxt();
if ctxt.is_root() {
return None;
}

let expn_data = ctxt.outer_expn_data();
let is_recursive = expn_data.call_site.source_equal(prev_span);

prev_span = self;
Expand Down
12 changes: 9 additions & 3 deletions compiler/rustc_span/src/source_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,15 @@ mod tests;
/// otherwise return the call site span up to the `enclosing_sp` by
/// following the `expn_data` chain.
pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span {
let expn_data1 = sp.ctxt().outer_expn_data();
let expn_data2 = enclosing_sp.ctxt().outer_expn_data();
if expn_data1.is_root() || !expn_data2.is_root() && expn_data1.call_site == expn_data2.call_site
let ctxt = sp.ctxt();
if ctxt.is_root() {
return sp;
}

let enclosing_ctxt = enclosing_sp.ctxt();
let expn_data1 = ctxt.outer_expn_data();
if !enclosing_ctxt.is_root()
&& expn_data1.call_site == enclosing_ctxt.outer_expn_data().call_site
{
sp
} else {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_span/src/source_map/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl SourceMap {
/// * the LHS span must start at or before the RHS span.
fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
// Ensure we're at the same expansion ID.
if sp_lhs.ctxt() != sp_rhs.ctxt() {
if !sp_lhs.eq_ctxt(sp_rhs) {
return None;
}

Expand Down
47 changes: 32 additions & 15 deletions compiler/rustc_span/src/span_encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,30 +210,47 @@ impl Span {
}
}

/// This function is used as a fast path when decoding the full `SpanData` is not necessary.
/// It's a cut-down version of `data_untracked`.
#[cfg_attr(not(test), rustc_diagnostic_item = "SpanCtxt")]
#[inline]
pub fn ctxt(self) -> SyntaxContext {
if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
// Returns either syntactic context, if it can be retrieved without taking the interner lock,
// or an index into the interner if it cannot.
fn inline_ctxt(self) -> Result<SyntaxContext, usize> {
Ok(if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
if self.len_with_tag_or_marker & PARENT_TAG == 0 {
// Inline-context format.
SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)
} else {
// Inline-parent format. We know that the SyntaxContext is root.
SyntaxContext::root()
}
} else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {
// Partially-interned format. This path avoids looking up the
// interned value, and is the whole point of the
// partially-interned format.
SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)
} else {
if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {
// Partially-interned format. This path avoids looking up the
// interned value, and is the whole point of the
// partially-interned format.
SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)
} else {
// Fully-interned format.
let index = self.lo_or_index;
with_span_interner(|interner| interner.spans[index as usize].ctxt)
// Fully-interned format.
return Err(self.lo_or_index as usize);
})
}

/// This function is used as a fast path when decoding the full `SpanData` is not necessary.
/// It's a cut-down version of `data_untracked`.
#[cfg_attr(not(test), rustc_diagnostic_item = "SpanCtxt")]
#[inline]
pub fn ctxt(self) -> SyntaxContext {
self.inline_ctxt()
.unwrap_or_else(|index| with_span_interner(|interner| interner.spans[index].ctxt))
}

#[inline]
pub fn eq_ctxt(self, other: Span) -> bool {
match (self.inline_ctxt(), other.inline_ctxt()) {
(Ok(ctxt1), Ok(ctxt2)) => ctxt1 == ctxt2,
(Ok(ctxt), Err(index)) | (Err(index), Ok(ctxt)) => {
with_span_interner(|interner| ctxt == interner.spans[index].ctxt)
}
(Err(index1), Err(index2)) => with_span_interner(|interner| {
interner.spans[index1].ctxt == interner.spans[index2].ctxt
}),
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ pub(super) fn check<'tcx>(
if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) {
if let Some(id) = path_to_local(cast_expr)
&& let Some(span) = cx.tcx.hir().opt_span(id)
&& span.ctxt() != cast_expr.span.ctxt()
&& !span.eq_ctxt(cast_expr.span)
{
// Binding context is different than the identifiers context.
// Weird macro wizardry could be involved here.
Expand Down
2 changes: 1 addition & 1 deletion src/tools/clippy/clippy_lints/src/implicit_hasher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
vis.visit_ty(impl_.self_ty);

for target in &vis.found {
if item.span.ctxt() != target.span().ctxt() {
if !item.span.eq_ctxt(target.span()) {
return;
}

Expand Down
2 changes: 1 addition & 1 deletion src/tools/clippy/clippy_lints/src/implicit_return.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn {
_: LocalDefId,
) {
if (!matches!(kind, FnKind::Closure) && matches!(decl.output, FnRetTy::DefaultReturn(_)))
|| span.ctxt() != body.value.span.ctxt()
|| !span.eq_ctxt(body.value.span)
|| in_external_macro(cx.sess(), span)
{
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ pub(super) fn check<'tcx>(
}
}

if unwrap_arg.span.ctxt() != map_span.ctxt() {
if !unwrap_arg.span.eq_ctxt(map_span) {
return;
}

Expand Down