mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Auto merge of #119531 - petrochenkov:cmpctxt, r=cjgillot
rustc_span: Optimize syntax context comparisons Including comparisons with root context. - `eq_ctxt` doesn't require retrieving full `SpanData`, or taking the span interner lock twice. - Checking `SyntaxContext` for "rootness" is cheaper than extracting a full outer `ExpnData` for it and checking *it* for rootness. The internal lint for `eq_ctxt` is also tweaked to detect `a.ctxt() != b.ctxt()` in addition to `a.ctxt() == b.ctxt()`.
This commit is contained in:
commit
9212108a9b
@ -72,7 +72,7 @@ pub(super) fn parse(
|
|||||||
// `SyntaxContext::root()` from a foreign crate will
|
// `SyntaxContext::root()` from a foreign crate will
|
||||||
// have the edition of that crate (which we manually
|
// have the edition of that crate (which we manually
|
||||||
// retrieve via the `edition` parameter).
|
// retrieve via the `edition` parameter).
|
||||||
if span.ctxt().is_root() {
|
if !span.from_expansion() {
|
||||||
edition
|
edition
|
||||||
} else {
|
} else {
|
||||||
span.edition()
|
span.edition()
|
||||||
|
@ -549,7 +549,9 @@ declare_lint_pass!(SpanUseEqCtxt => [SPAN_USE_EQ_CTXT]);
|
|||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for SpanUseEqCtxt {
|
impl<'tcx> LateLintPass<'tcx> for SpanUseEqCtxt {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
|
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) {
|
if is_span_ctxt_call(cx, lhs) && is_span_ctxt_call(cx, rhs) {
|
||||||
cx.emit_spanned_lint(SPAN_USE_EQ_CTXT, expr.span, SpanUseEqCtxtDiag);
|
cx.emit_spanned_lint(SPAN_USE_EQ_CTXT, expr.span, SpanUseEqCtxtDiag);
|
||||||
}
|
}
|
||||||
|
@ -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_span = arg.span;
|
||||||
let mut arg_macro = None;
|
let mut arg_macro = None;
|
||||||
while !span.contains(arg_span) {
|
while !span.contains(arg_span) {
|
||||||
let expn = arg_span.ctxt().outer_expn_data();
|
let ctxt = arg_span.ctxt();
|
||||||
if expn.is_root() {
|
if ctxt.is_root() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
let expn = ctxt.outer_expn_data();
|
||||||
arg_macro = expn.macro_def_id;
|
arg_macro = expn.macro_def_id;
|
||||||
arg_span = expn.call_site;
|
arg_span = expn.call_site;
|
||||||
}
|
}
|
||||||
|
@ -1621,7 +1621,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
|
|||||||
let from_macro = non_shorthands
|
let from_macro = non_shorthands
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(_, pat_span, ident_span)| {
|
.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);
|
.map(|(_, pat_span, _)| *pat_span);
|
||||||
let non_shorthands = non_shorthands
|
let non_shorthands = non_shorthands
|
||||||
|
@ -295,11 +295,13 @@ impl ExpnId {
|
|||||||
pub fn expansion_cause(mut self) -> Option<Span> {
|
pub fn expansion_cause(mut self) -> Option<Span> {
|
||||||
let mut last_macro = None;
|
let mut last_macro = None;
|
||||||
loop {
|
loop {
|
||||||
|
// Fast path to avoid locking.
|
||||||
|
if self == ExpnId::root() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
let expn_data = self.expn_data();
|
let expn_data = self.expn_data();
|
||||||
// Stop going up the backtrace once include! is encountered
|
// Stop going up the backtrace once include! is encountered
|
||||||
if expn_data.is_root()
|
if expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include) {
|
||||||
|| expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include)
|
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
self = expn_data.call_site.ctxt().outer_expn();
|
self = expn_data.call_site.ctxt().outer_expn();
|
||||||
@ -433,7 +435,7 @@ impl HygieneData {
|
|||||||
|
|
||||||
fn marks(&self, mut ctxt: SyntaxContext) -> Vec<(ExpnId, Transparency)> {
|
fn marks(&self, mut ctxt: SyntaxContext) -> Vec<(ExpnId, Transparency)> {
|
||||||
let mut marks = Vec::new();
|
let mut marks = Vec::new();
|
||||||
while ctxt != SyntaxContext::root() {
|
while !ctxt.is_root() {
|
||||||
debug!("marks: getting parent of {:?}", ctxt);
|
debug!("marks: getting parent of {:?}", ctxt);
|
||||||
marks.push(self.outer_mark(ctxt));
|
marks.push(self.outer_mark(ctxt));
|
||||||
ctxt = self.parent_ctxt(ctxt);
|
ctxt = self.parent_ctxt(ctxt);
|
||||||
|
@ -544,10 +544,6 @@ impl Span {
|
|||||||
self.data().with_hi(hi)
|
self.data().with_hi(hi)
|
||||||
}
|
}
|
||||||
#[inline]
|
#[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 {
|
pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
|
||||||
self.data_untracked().with_ctxt(ctxt)
|
self.data_untracked().with_ctxt(ctxt)
|
||||||
}
|
}
|
||||||
@ -568,7 +564,7 @@ impl Span {
|
|||||||
/// Returns `true` if this span comes from any kind of macro, desugaring or inlining.
|
/// Returns `true` if this span comes from any kind of macro, desugaring or inlining.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_expansion(self) -> bool {
|
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
|
/// Returns `true` if `span` originates in a macro's expansion where debuginfo should be
|
||||||
@ -657,15 +653,15 @@ impl Span {
|
|||||||
/// Returns the source span -- this is either the supplied span, or the span for
|
/// Returns the source span -- this is either the supplied span, or the span for
|
||||||
/// the macro callsite that expanded to it.
|
/// the macro callsite that expanded to it.
|
||||||
pub fn source_callsite(self) -> Span {
|
pub fn source_callsite(self) -> Span {
|
||||||
let expn_data = self.ctxt().outer_expn_data();
|
let ctxt = self.ctxt();
|
||||||
if !expn_data.is_root() { expn_data.call_site.source_callsite() } else { self }
|
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,
|
/// The `Span` for the tokens in the previous macro expansion from which `self` was generated,
|
||||||
/// if any.
|
/// if any.
|
||||||
pub fn parent_callsite(self) -> Option<Span> {
|
pub fn parent_callsite(self) -> Option<Span> {
|
||||||
let expn_data = self.ctxt().outer_expn_data();
|
let ctxt = self.ctxt();
|
||||||
if !expn_data.is_root() { Some(expn_data.call_site) } else { None }
|
(!ctxt.is_root()).then(|| ctxt.outer_expn_data().call_site)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Walk down the expansion ancestors to find a span that's contained within `outer`.
|
/// Walk down the expansion ancestors to find a span that's contained within `outer`.
|
||||||
@ -750,15 +746,14 @@ impl Span {
|
|||||||
/// else returns the `ExpnData` for the macro definition
|
/// else returns the `ExpnData` for the macro definition
|
||||||
/// corresponding to the source callsite.
|
/// corresponding to the source callsite.
|
||||||
pub fn source_callee(self) -> Option<ExpnData> {
|
pub fn source_callee(self) -> Option<ExpnData> {
|
||||||
let expn_data = self.ctxt().outer_expn_data();
|
let mut ctxt = self.ctxt();
|
||||||
|
let mut opt_expn_data = None;
|
||||||
// Create an iterator of call site expansions
|
while !ctxt.is_root() {
|
||||||
iter::successors(Some(expn_data), |expn_data| {
|
let expn_data = ctxt.outer_expn_data();
|
||||||
Some(expn_data.call_site.ctxt().outer_expn_data())
|
ctxt = expn_data.call_site.ctxt();
|
||||||
})
|
opt_expn_data = Some(expn_data);
|
||||||
// Find the last expansion which is not root
|
}
|
||||||
.take_while(|expn_data| !expn_data.is_root())
|
opt_expn_data
|
||||||
.last()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if a span is "internal" to a macro in which `#[unstable]`
|
/// Checks if a span is "internal" to a macro in which `#[unstable]`
|
||||||
@ -799,11 +794,12 @@ impl Span {
|
|||||||
let mut prev_span = DUMMY_SP;
|
let mut prev_span = DUMMY_SP;
|
||||||
iter::from_fn(move || {
|
iter::from_fn(move || {
|
||||||
loop {
|
loop {
|
||||||
let expn_data = self.ctxt().outer_expn_data();
|
let ctxt = self.ctxt();
|
||||||
if expn_data.is_root() {
|
if ctxt.is_root() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let expn_data = ctxt.outer_expn_data();
|
||||||
let is_recursive = expn_data.call_site.source_equal(prev_span);
|
let is_recursive = expn_data.call_site.source_equal(prev_span);
|
||||||
|
|
||||||
prev_span = self;
|
prev_span = self;
|
||||||
|
@ -23,9 +23,15 @@ mod tests;
|
|||||||
/// otherwise return the call site span up to the `enclosing_sp` by
|
/// otherwise return the call site span up to the `enclosing_sp` by
|
||||||
/// following the `expn_data` chain.
|
/// following the `expn_data` chain.
|
||||||
pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span {
|
pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span {
|
||||||
let expn_data1 = sp.ctxt().outer_expn_data();
|
let ctxt = sp.ctxt();
|
||||||
let expn_data2 = enclosing_sp.ctxt().outer_expn_data();
|
if ctxt.is_root() {
|
||||||
if expn_data1.is_root() || !expn_data2.is_root() && expn_data1.call_site == expn_data2.call_site
|
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
|
sp
|
||||||
} else {
|
} else {
|
||||||
|
@ -18,7 +18,7 @@ impl SourceMap {
|
|||||||
/// * the LHS span must start at or before the RHS span.
|
/// * the LHS span must start at or before the RHS span.
|
||||||
fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
|
fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
|
||||||
// Ensure we're at the same expansion ID.
|
// Ensure we're at the same expansion ID.
|
||||||
if sp_lhs.ctxt() != sp_rhs.ctxt() {
|
if !sp_lhs.eq_ctxt(sp_rhs) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,12 +210,10 @@ impl Span {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is used as a fast path when decoding the full `SpanData` is not necessary.
|
// Returns either syntactic context, if it can be retrieved without taking the interner lock,
|
||||||
/// It's a cut-down version of `data_untracked`.
|
// or an index into the interner if it cannot.
|
||||||
#[cfg_attr(not(test), rustc_diagnostic_item = "SpanCtxt")]
|
fn inline_ctxt(self) -> Result<SyntaxContext, usize> {
|
||||||
#[inline]
|
Ok(if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
|
||||||
pub fn ctxt(self) -> SyntaxContext {
|
|
||||||
if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
|
|
||||||
if self.len_with_tag_or_marker & PARENT_TAG == 0 {
|
if self.len_with_tag_or_marker & PARENT_TAG == 0 {
|
||||||
// Inline-context format.
|
// Inline-context format.
|
||||||
SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)
|
SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)
|
||||||
@ -223,17 +221,36 @@ impl Span {
|
|||||||
// Inline-parent format. We know that the SyntaxContext is root.
|
// Inline-parent format. We know that the SyntaxContext is root.
|
||||||
SyntaxContext::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 {
|
} else {
|
||||||
if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {
|
// Fully-interned format.
|
||||||
// Partially-interned format. This path avoids looking up the
|
return Err(self.lo_or_index as usize);
|
||||||
// interned value, and is the whole point of the
|
})
|
||||||
// partially-interned format.
|
}
|
||||||
SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)
|
|
||||||
} else {
|
/// This function is used as a fast path when decoding the full `SpanData` is not necessary.
|
||||||
// Fully-interned format.
|
/// It's a cut-down version of `data_untracked`.
|
||||||
let index = self.lo_or_index;
|
#[cfg_attr(not(test), rustc_diagnostic_item = "SpanCtxt")]
|
||||||
with_span_interner(|interner| interner.spans[index as usize].ctxt)
|
#[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
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,7 +145,7 @@ pub(super) fn check<'tcx>(
|
|||||||
if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) {
|
if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) {
|
||||||
if let Some(id) = path_to_local(cast_expr)
|
if let Some(id) = path_to_local(cast_expr)
|
||||||
&& let Some(span) = cx.tcx.hir().opt_span(id)
|
&& 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.
|
// Binding context is different than the identifiers context.
|
||||||
// Weird macro wizardry could be involved here.
|
// Weird macro wizardry could be involved here.
|
||||||
|
@ -118,7 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
|
|||||||
vis.visit_ty(impl_.self_ty);
|
vis.visit_ty(impl_.self_ty);
|
||||||
|
|
||||||
for target in &vis.found {
|
for target in &vis.found {
|
||||||
if item.span.ctxt() != target.span().ctxt() {
|
if !item.span.eq_ctxt(target.span()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn {
|
|||||||
_: LocalDefId,
|
_: LocalDefId,
|
||||||
) {
|
) {
|
||||||
if (!matches!(kind, FnKind::Closure) && matches!(decl.output, FnRetTy::DefaultReturn(_)))
|
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)
|
|| in_external_macro(cx.sess(), span)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user