From caea42f6c8ba8f5cc5ed04557ec5d072b107e7b4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 27 May 2019 13:52:11 +1000 Subject: [PATCH] Introduce and use `SyntaxContext::outer_expn_info()`. It reduces two `hygiene_data` accesses to one on some hot paths. --- src/librustc/lint/internal.rs | 2 +- src/librustc/lint/mod.rs | 4 ++-- src/librustc/traits/error_reporting.rs | 2 +- src/librustc_codegen_ssa/mir/mod.rs | 2 +- src/librustc_lint/builtin.rs | 4 ++-- src/librustc_lint/unused.rs | 5 ++--- src/librustc_resolve/lib.rs | 4 ++-- src/librustc_resolve/macros.rs | 2 +- src/librustc_typeck/check/demand.rs | 2 +- src/librustc_typeck/check/method/suggest.rs | 4 ++-- src/libsyntax/ext/base.rs | 2 +- src/libsyntax/source_map.rs | 4 ++-- src/libsyntax_ext/proc_macro_server.rs | 2 +- src/libsyntax_pos/hygiene.rs | 10 ++++++++++ src/libsyntax_pos/lib.rs | 20 ++++++++++---------- 15 files changed, 39 insertions(+), 30 deletions(-) diff --git a/src/librustc/lint/internal.rs b/src/librustc/lint/internal.rs index e953c0845996..86dae579ca75 100644 --- a/src/librustc/lint/internal.rs +++ b/src/librustc/lint/internal.rs @@ -113,7 +113,7 @@ fn check_ty(&mut self, cx: &LateContext<'_, '_>, ty: &'tcx Ty) { .help("try using `Ty` instead") .emit(); } else { - if ty.span.ctxt().outer().expn_info().is_some() { + if ty.span.ctxt().outer_expn_info().is_some() { return; } if let Some(t) = is_ty_or_ty_ctxt(cx, ty) { diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index c3afca35303c..f4eff6121c04 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -880,7 +880,7 @@ pub fn provide(providers: &mut Providers<'_>) { /// This is used to test whether a lint should not even begin to figure out whether it should /// be reported on the current node. pub fn in_external_macro(sess: &Session, span: Span) -> bool { - let info = match span.ctxt().outer().expn_info() { + let info = match span.ctxt().outer_expn_info() { Some(info) => info, // no ExpnInfo means this span doesn't come from a macro None => return false, @@ -908,7 +908,7 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool { /// Returns whether `span` originates in a derive macro's expansion pub fn in_derive_expansion(span: Span) -> bool { - let info = match span.ctxt().outer().expn_info() { + let info = match span.ctxt().outer_expn_info() { Some(info) => info, // no ExpnInfo means this span doesn't come from a macro None => return false, diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 9019c4a0575d..55b5cba2b02c 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -65,7 +65,7 @@ struct ErrorDescriptor<'tcx> { format: ExpnFormat::CompilerDesugaring(_), def_site: Some(def_span), .. - }) = span.ctxt().outer().expn_info() { + }) = span.ctxt().outer_expn_info() { span = def_span; } diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index fed12c9a29fd..8f4f0b5b23fd 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -131,7 +131,7 @@ pub fn debug_loc(&self, source_info: mir::SourceInfo) -> (Option, S // at the level above that. let mut span = source_info.span; while span.ctxt() != NO_EXPANSION && span.ctxt() != self.mir.span.ctxt() { - if let Some(info) = span.ctxt().outer().expn_info() { + if let Some(info) = span.ctxt().outer_expn_info() { span = info.call_site; } else { break; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index d184c671bbaf..44b727c6925d 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -158,7 +158,7 @@ fn check_pat(&mut self, cx: &LateContext<'_, '_>, pat: &hir::Pat) { if fieldpat.node.is_shorthand { continue; } - if fieldpat.span.ctxt().outer().expn_info().is_some() { + if fieldpat.span.ctxt().outer_expn_info().is_some() { // Don't lint if this is a macro expansion: macro authors // shouldn't have to worry about this kind of style issue // (Issue #49588) @@ -1003,7 +1003,7 @@ fn perform_lint(&self, cx: &LateContext<'_, '_>, what: &str, id: hir::HirId, let mut applicability = Applicability::MachineApplicable; match vis.node { hir::VisibilityKind::Public if !cx.access_levels.is_reachable(id) => { - if span.ctxt().outer().expn_info().is_some() { + if span.ctxt().outer_expn_info().is_some() { applicability = Applicability::MaybeIncorrect; } let def_span = cx.tcx.sess.source_map().def_span(span); diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 34f7e04c1642..036820c6d7fa 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -391,9 +391,8 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { // trigger in situations that macro authors shouldn't have to care about, e.g., // when a parenthesized token tree matched in one macro expansion is matched as // an expression in another and used as a fn/method argument (Issue #47775) - if e.span.ctxt().outer().expn_info() - .map_or(false, |info| info.call_site.ctxt().outer() - .expn_info().is_some()) { + if e.span.ctxt().outer_expn_info() + .map_or(false, |info| info.call_site.ctxt().outer_expn_info().is_some()) { return; } let msg = format!("{} argument", call_kind); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index f9cf95a873f5..9fe201b8c5e1 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -762,7 +762,7 @@ fn visit_mod( ItemKind::Use(..) => { // don't suggest placing a use before the prelude // import or other generated ones - if item.span.ctxt().outer().expn_info().is_none() { + if item.span.ctxt().outer_expn_info().is_none() { self.span = Some(item.span.shrink_to_lo()); self.found_use = true; return; @@ -772,7 +772,7 @@ fn visit_mod( ItemKind::ExternCrate(_) => {} // but place them before the first other item _ => if self.span.map_or(true, |span| item.span < span ) { - if item.span.ctxt().outer().expn_info().is_none() { + if item.span.ctxt().outer_expn_info().is_none() { // don't insert between attributes and an item if item.attrs.is_empty() { self.span = Some(item.span.shrink_to_lo()); diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 9bb607a2cc28..08ab5b853252 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -413,7 +413,7 @@ pub fn resolve_macro_to_res_inner( // Possibly apply the macro helper hack if kind == MacroKind::Bang && path.len() == 1 && - path[0].ident.span.ctxt().outer().expn_info() + path[0].ident.span.ctxt().outer_expn_info() .map_or(false, |info| info.local_inner_macros) { let root = Ident::new(kw::DollarCrate, path[0].ident.span); path.insert(0, Segment::from_ident(root)); diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 724f8d886e8a..91c8bb6a7437 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -327,7 +327,7 @@ pub fn check_ref( // Check the `expn_info()` to see if this is a macro; if so, it's hard to // extract the text and make a good suggestion, so don't bother. - let is_macro = sp.ctxt().outer().expn_info().is_some(); + let is_macro = sp.ctxt().outer_expn_info().is_some(); match (&expr.node, &expected.sty, &checked_ty.sty) { (_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (&exp.sty, &check.sty) { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index dfe21edee41f..a1658fd89cde 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -892,7 +892,7 @@ fn visit_mod( hir::ItemKind::Use(..) => { // Don't suggest placing a `use` before the prelude // import or other generated ones. - if item.span.ctxt().outer().expn_info().is_none() { + if item.span.ctxt().outer_expn_info().is_none() { self.span = Some(item.span.shrink_to_lo()); self.found_use = true; return; @@ -902,7 +902,7 @@ fn visit_mod( hir::ItemKind::ExternCrate(_) => {} // ...but do place them before the first other item. _ => if self.span.map_or(true, |span| item.span < span ) { - if item.span.ctxt().outer().expn_info().is_none() { + if item.span.ctxt().outer_expn_info().is_none() { // Don't insert between attributes and an item. if item.attrs.is_empty() { self.span = Some(item.span.shrink_to_lo()); diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index d72193ffe120..4b5b9ff7bbee 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -872,7 +872,7 @@ pub fn expansion_cause(&self) -> Option { let mut ctxt = self.backtrace(); let mut last_macro = None; loop { - if ctxt.outer().expn_info().map_or(None, |info| { + if ctxt.outer_expn_info().map_or(None, |info| { if info.format.name() == sym::include { // Stop going up the backtrace once include! is encountered return None; diff --git a/src/libsyntax/source_map.rs b/src/libsyntax/source_map.rs index 8a210db91858..e83cad93d1c4 100644 --- a/src/libsyntax/source_map.rs +++ b/src/libsyntax/source_map.rs @@ -30,8 +30,8 @@ /// otherwise return the call site span up to the `enclosing_sp` by /// following the `expn_info` chain. pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span { - let call_site1 = sp.ctxt().outer().expn_info().map(|ei| ei.call_site); - let call_site2 = enclosing_sp.ctxt().outer().expn_info().map(|ei| ei.call_site); + let call_site1 = sp.ctxt().outer_expn_info().map(|ei| ei.call_site); + let call_site2 = enclosing_sp.ctxt().outer_expn_info().map(|ei| ei.call_site); match (call_site1, call_site2) { (None, _) => sp, (Some(call_site1), Some(call_site2)) if call_site1 == call_site2 => sp, diff --git a/src/libsyntax_ext/proc_macro_server.rs b/src/libsyntax_ext/proc_macro_server.rs index 53730d2d0802..cc05ecf8df5a 100644 --- a/src/libsyntax_ext/proc_macro_server.rs +++ b/src/libsyntax_ext/proc_macro_server.rs @@ -680,7 +680,7 @@ fn source_file(&mut self, span: Self::Span) -> Self::SourceFile { self.sess.source_map().lookup_char_pos(span.lo()).file } fn parent(&mut self, span: Self::Span) -> Option { - span.ctxt().outer().expn_info().map(|i| i.call_site) + span.ctxt().outer_expn_info().map(|i| i.call_site) } fn source(&mut self, span: Self::Span) -> Self::Span { span.source_callsite() diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 3ffeaf43b85e..b4bb6d9c5e84 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -517,6 +517,16 @@ pub fn outer(self) -> Mark { HygieneData::with(|data| data.syntax_contexts[self.0 as usize].outer_mark) } + /// `ctxt.outer_expn_info()` is equivalent to but faster than + /// `ctxt.outer().expn_info()`. + #[inline] + pub fn outer_expn_info(self) -> Option { + HygieneData::with(|data| { + let outer = data.syntax_contexts[self.0 as usize].outer_mark; + data.marks[outer.0 as usize].expn_info.clone() + }) + } + pub fn dollar_crate_name(self) -> Symbol { HygieneData::with(|data| data.syntax_contexts[self.0 as usize].dollar_crate_name) } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index cb5aaf7eb882..30e075a33961 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -348,18 +348,18 @@ pub fn trim_start(self, other: Span) -> Option { /// 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 { - self.ctxt().outer().expn_info().map(|info| info.call_site.source_callsite()).unwrap_or(self) + self.ctxt().outer_expn_info().map(|info| info.call_site.source_callsite()).unwrap_or(self) } /// The `Span` for the tokens in the previous macro expansion from which `self` was generated, /// if any. pub fn parent(self) -> Option { - self.ctxt().outer().expn_info().map(|i| i.call_site) + self.ctxt().outer_expn_info().map(|i| i.call_site) } /// Edition of the crate from which this span came. pub fn edition(self) -> edition::Edition { - self.ctxt().outer().expn_info().map_or_else(|| { + self.ctxt().outer_expn_info().map_or_else(|| { Edition::from_session() }, |einfo| einfo.edition) } @@ -381,19 +381,19 @@ pub fn rust_2018(&self) -> bool { /// corresponding to the source callsite. pub fn source_callee(self) -> Option { fn source_callee(info: ExpnInfo) -> ExpnInfo { - match info.call_site.ctxt().outer().expn_info() { + match info.call_site.ctxt().outer_expn_info() { Some(info) => source_callee(info), None => info, } } - self.ctxt().outer().expn_info().map(source_callee) + self.ctxt().outer_expn_info().map(source_callee) } /// Checks if a span is "internal" to a macro in which `#[unstable]` /// items can be used (that is, a macro marked with /// `#[allow_internal_unstable]`). pub fn allows_unstable(&self, feature: Symbol) -> bool { - match self.ctxt().outer().expn_info() { + match self.ctxt().outer_expn_info() { Some(info) => info .allow_internal_unstable .map_or(false, |features| features.iter().any(|&f| @@ -405,7 +405,7 @@ pub fn allows_unstable(&self, feature: Symbol) -> bool { /// Checks if this span arises from a compiler desugaring of kind `kind`. pub fn is_compiler_desugaring(&self, kind: CompilerDesugaringKind) -> bool { - match self.ctxt().outer().expn_info() { + match self.ctxt().outer_expn_info() { Some(info) => match info.format { ExpnFormat::CompilerDesugaring(k) => k == kind, _ => false, @@ -417,7 +417,7 @@ pub fn is_compiler_desugaring(&self, kind: CompilerDesugaringKind) -> bool { /// Returns the compiler desugaring that created this span, or `None` /// if this span is not from a desugaring. pub fn compiler_desugaring_kind(&self) -> Option { - match self.ctxt().outer().expn_info() { + match self.ctxt().outer_expn_info() { Some(info) => match info.format { ExpnFormat::CompilerDesugaring(k) => Some(k), _ => None @@ -430,7 +430,7 @@ pub fn compiler_desugaring_kind(&self) -> Option { /// can be used without triggering the `unsafe_code` lint // (that is, a macro marked with `#[allow_internal_unsafe]`). pub fn allows_unsafe(&self) -> bool { - match self.ctxt().outer().expn_info() { + match self.ctxt().outer_expn_info() { Some(info) => info.allow_internal_unsafe, None => false, } @@ -439,7 +439,7 @@ pub fn allows_unsafe(&self) -> bool { pub fn macro_backtrace(mut self) -> Vec { let mut prev_span = DUMMY_SP; let mut result = vec![]; - while let Some(info) = self.ctxt().outer().expn_info() { + while let Some(info) = self.ctxt().outer_expn_info() { // Don't print recursive invocations. if !info.call_site.source_equal(&prev_span) { let (pre, post) = match info.format {