Skip to content

Commit 90d11d6

Browse files
committed
rustc_span: Optimize syntax context comparisons
Including comparisons with root context
1 parent b8c2074 commit 90d11d6

File tree

13 files changed

+76
-52
lines changed

13 files changed

+76
-52
lines changed

compiler/rustc_expand/src/mbe/quoted.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub(super) fn parse(
7272
// `SyntaxContext::root()` from a foreign crate will
7373
// have the edition of that crate (which we manually
7474
// retrieve via the `edition` parameter).
75-
if span.ctxt().is_root() {
75+
if !span.from_expansion() {
7676
edition
7777
} else {
7878
span.edition()

compiler/rustc_lint/src/internal.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,9 @@ declare_lint_pass!(SpanUseEqCtxt => [SPAN_USE_EQ_CTXT]);
549549

550550
impl<'tcx> LateLintPass<'tcx> for SpanUseEqCtxt {
551551
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
552-
if let ExprKind::Binary(BinOp { node: BinOpKind::Eq, .. }, lhs, rhs) = expr.kind {
552+
if let ExprKind::Binary(BinOp { node: BinOpKind::Eq | BinOpKind::Ne, .. }, lhs, rhs) =
553+
expr.kind
554+
{
553555
if is_span_ctxt_call(cx, lhs) && is_span_ctxt_call(cx, rhs) {
554556
cx.emit_spanned_lint(SPAN_USE_EQ_CTXT, expr.span, SpanUseEqCtxtDiag);
555557
}

compiler/rustc_lint/src/non_fmt_panic.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,11 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
111111
let mut arg_span = arg.span;
112112
let mut arg_macro = None;
113113
while !span.contains(arg_span) {
114-
let expn = arg_span.ctxt().outer_expn_data();
115-
if expn.is_root() {
114+
let ctxt = arg_span.ctxt();
115+
if ctxt.is_root() {
116116
break;
117117
}
118+
let expn = ctxt.outer_expn_data();
118119
arg_macro = expn.macro_def_id;
119120
arg_span = expn.call_site;
120121
}

compiler/rustc_passes/src/liveness.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1630,7 +1630,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
16301630
let from_macro = non_shorthands
16311631
.iter()
16321632
.find(|(_, pat_span, ident_span)| {
1633-
pat_span.ctxt() != ident_span.ctxt() && pat_span.from_expansion()
1633+
!pat_span.eq_ctxt(*ident_span) && pat_span.from_expansion()
16341634
})
16351635
.map(|(_, pat_span, _)| *pat_span);
16361636
let non_shorthands = non_shorthands

compiler/rustc_span/src/hygiene.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -295,11 +295,13 @@ impl ExpnId {
295295
pub fn expansion_cause(mut self) -> Option<Span> {
296296
let mut last_macro = None;
297297
loop {
298+
// Fast path to avoid locking.
299+
if self == ExpnId::root() {
300+
break;
301+
}
298302
let expn_data = self.expn_data();
299303
// Stop going up the backtrace once include! is encountered
300-
if expn_data.is_root()
301-
|| expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include)
302-
{
304+
if expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include) {
303305
break;
304306
}
305307
self = expn_data.call_site.ctxt().outer_expn();
@@ -433,7 +435,7 @@ impl HygieneData {
433435

434436
fn marks(&self, mut ctxt: SyntaxContext) -> Vec<(ExpnId, Transparency)> {
435437
let mut marks = Vec::new();
436-
while ctxt != SyntaxContext::root() {
438+
while !ctxt.is_root() {
437439
debug!("marks: getting parent of {:?}", ctxt);
438440
marks.push(self.outer_mark(ctxt));
439441
ctxt = self.parent_ctxt(ctxt);

compiler/rustc_span/src/lib.rs

+16-20
Original file line numberDiff line numberDiff line change
@@ -541,10 +541,6 @@ impl Span {
541541
self.data().with_hi(hi)
542542
}
543543
#[inline]
544-
pub fn eq_ctxt(self, other: Span) -> bool {
545-
self.data_untracked().ctxt == other.data_untracked().ctxt
546-
}
547-
#[inline]
548544
pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
549545
self.data_untracked().with_ctxt(ctxt)
550546
}
@@ -565,7 +561,7 @@ impl Span {
565561
/// Returns `true` if this span comes from any kind of macro, desugaring or inlining.
566562
#[inline]
567563
pub fn from_expansion(self) -> bool {
568-
self.ctxt() != SyntaxContext::root()
564+
!self.ctxt().is_root()
569565
}
570566

571567
/// Returns `true` if `span` originates in a macro's expansion where debuginfo should be
@@ -654,15 +650,15 @@ impl Span {
654650
/// Returns the source span -- this is either the supplied span, or the span for
655651
/// the macro callsite that expanded to it.
656652
pub fn source_callsite(self) -> Span {
657-
let expn_data = self.ctxt().outer_expn_data();
658-
if !expn_data.is_root() { expn_data.call_site.source_callsite() } else { self }
653+
let ctxt = self.ctxt();
654+
if !ctxt.is_root() { ctxt.outer_expn_data().call_site.source_callsite() } else { self }
659655
}
660656

661657
/// The `Span` for the tokens in the previous macro expansion from which `self` was generated,
662658
/// if any.
663659
pub fn parent_callsite(self) -> Option<Span> {
664-
let expn_data = self.ctxt().outer_expn_data();
665-
if !expn_data.is_root() { Some(expn_data.call_site) } else { None }
660+
let ctxt = self.ctxt();
661+
(!ctxt.is_root()).then(|| ctxt.outer_expn_data().call_site)
666662
}
667663

668664
/// Walk down the expansion ancestors to find a span that's contained within `outer`.
@@ -747,15 +743,14 @@ impl Span {
747743
/// else returns the `ExpnData` for the macro definition
748744
/// corresponding to the source callsite.
749745
pub fn source_callee(self) -> Option<ExpnData> {
750-
let expn_data = self.ctxt().outer_expn_data();
751-
752-
// Create an iterator of call site expansions
753-
iter::successors(Some(expn_data), |expn_data| {
754-
Some(expn_data.call_site.ctxt().outer_expn_data())
755-
})
756-
// Find the last expansion which is not root
757-
.take_while(|expn_data| !expn_data.is_root())
758-
.last()
746+
let mut ctxt = self.ctxt();
747+
let mut opt_expn_data = None;
748+
while !ctxt.is_root() {
749+
let expn_data = ctxt.outer_expn_data();
750+
ctxt = expn_data.call_site.ctxt();
751+
opt_expn_data = Some(expn_data);
752+
}
753+
opt_expn_data
759754
}
760755

761756
/// Checks if a span is "internal" to a macro in which `#[unstable]`
@@ -796,11 +791,12 @@ impl Span {
796791
let mut prev_span = DUMMY_SP;
797792
iter::from_fn(move || {
798793
loop {
799-
let expn_data = self.ctxt().outer_expn_data();
800-
if expn_data.is_root() {
794+
let ctxt = self.ctxt();
795+
if ctxt.is_root() {
801796
return None;
802797
}
803798

799+
let expn_data = ctxt.outer_expn_data();
804800
let is_recursive = expn_data.call_site.source_equal(prev_span);
805801

806802
prev_span = self;

compiler/rustc_span/src/source_map.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,15 @@ mod tests;
2323
/// otherwise return the call site span up to the `enclosing_sp` by
2424
/// following the `expn_data` chain.
2525
pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span {
26-
let expn_data1 = sp.ctxt().outer_expn_data();
27-
let expn_data2 = enclosing_sp.ctxt().outer_expn_data();
28-
if expn_data1.is_root() || !expn_data2.is_root() && expn_data1.call_site == expn_data2.call_site
26+
let ctxt = sp.ctxt();
27+
if ctxt.is_root() {
28+
return sp;
29+
}
30+
31+
let enclosing_ctxt = enclosing_sp.ctxt();
32+
let expn_data1 = ctxt.outer_expn_data();
33+
if !enclosing_ctxt.is_root()
34+
&& expn_data1.call_site == enclosing_ctxt.outer_expn_data().call_site
2935
{
3036
sp
3137
} else {

compiler/rustc_span/src/source_map/tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl SourceMap {
1818
/// * the LHS span must start at or before the RHS span.
1919
fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
2020
// Ensure we're at the same expansion ID.
21-
if sp_lhs.ctxt() != sp_rhs.ctxt() {
21+
if !sp_lhs.eq_ctxt(sp_rhs) {
2222
return None;
2323
}
2424

compiler/rustc_span/src/span_encoding.rs

+32-15
Original file line numberDiff line numberDiff line change
@@ -210,30 +210,47 @@ impl Span {
210210
}
211211
}
212212

213-
/// This function is used as a fast path when decoding the full `SpanData` is not necessary.
214-
/// It's a cut-down version of `data_untracked`.
215-
#[cfg_attr(not(test), rustc_diagnostic_item = "SpanCtxt")]
216-
#[inline]
217-
pub fn ctxt(self) -> SyntaxContext {
218-
if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
213+
// Returns either syntactic context, if it can be retrieved without taking the interner lock,
214+
// or an index into the interner if it cannot.
215+
fn inline_ctxt(self) -> Result<SyntaxContext, usize> {
216+
Ok(if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
219217
if self.len_with_tag_or_marker & PARENT_TAG == 0 {
220218
// Inline-context format.
221219
SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)
222220
} else {
223221
// Inline-parent format. We know that the SyntaxContext is root.
224222
SyntaxContext::root()
225223
}
224+
} else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {
225+
// Partially-interned format. This path avoids looking up the
226+
// interned value, and is the whole point of the
227+
// partially-interned format.
228+
SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)
226229
} else {
227-
if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {
228-
// Partially-interned format. This path avoids looking up the
229-
// interned value, and is the whole point of the
230-
// partially-interned format.
231-
SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)
232-
} else {
233-
// Fully-interned format.
234-
let index = self.lo_or_index;
235-
with_span_interner(|interner| interner.spans[index as usize].ctxt)
230+
// Fully-interned format.
231+
return Err(self.lo_or_index as usize);
232+
})
233+
}
234+
235+
/// This function is used as a fast path when decoding the full `SpanData` is not necessary.
236+
/// It's a cut-down version of `data_untracked`.
237+
#[cfg_attr(not(test), rustc_diagnostic_item = "SpanCtxt")]
238+
#[inline]
239+
pub fn ctxt(self) -> SyntaxContext {
240+
self.inline_ctxt()
241+
.unwrap_or_else(|index| with_span_interner(|interner| interner.spans[index].ctxt))
242+
}
243+
244+
#[inline]
245+
pub fn eq_ctxt(self, other: Span) -> bool {
246+
match (self.inline_ctxt(), other.inline_ctxt()) {
247+
(Ok(ctxt1), Ok(ctxt2)) => ctxt1 == ctxt2,
248+
(Ok(ctxt), Err(index)) | (Err(index), Ok(ctxt)) => {
249+
with_span_interner(|interner| ctxt == interner.spans[index].ctxt)
236250
}
251+
(Err(index1), Err(index2)) => with_span_interner(|interner| {
252+
interner.spans[index1].ctxt == interner.spans[index2].ctxt
253+
}),
237254
}
238255
}
239256
}

src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ pub(super) fn check<'tcx>(
145145
if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) {
146146
if let Some(id) = path_to_local(cast_expr)
147147
&& let Some(span) = cx.tcx.hir().opt_span(id)
148-
&& span.ctxt() != cast_expr.span.ctxt()
148+
&& !span.eq_ctxt(cast_expr.span)
149149
{
150150
// Binding context is different than the identifiers context.
151151
// Weird macro wizardry could be involved here.

src/tools/clippy/clippy_lints/src/implicit_hasher.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
118118
vis.visit_ty(impl_.self_ty);
119119

120120
for target in &vis.found {
121-
if item.span.ctxt() != target.span().ctxt() {
121+
if !item.span.eq_ctxt(target.span()) {
122122
return;
123123
}
124124

src/tools/clippy/clippy_lints/src/implicit_return.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn {
225225
_: LocalDefId,
226226
) {
227227
if (!matches!(kind, FnKind::Closure) && matches!(decl.output, FnRetTy::DefaultReturn(_)))
228-
|| span.ctxt() != body.value.span.ctxt()
228+
|| !span.eq_ctxt(body.value.span)
229229
|| in_external_macro(cx.sess(), span)
230230
{
231231
return;

src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ pub(super) fn check<'tcx>(
6767
}
6868
}
6969

70-
if unwrap_arg.span.ctxt() != map_span.ctxt() {
70+
if !unwrap_arg.span.eq_ctxt(map_span) {
7171
return;
7272
}
7373

0 commit comments

Comments
 (0)