From eac900ac87828d6a4813f0c4a870bcdb439d1175 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 7 Jul 2019 16:45:41 +0300 Subject: [PATCH] hygiene: Make sure each `Mark` has an associated expansion info The root expansion was missing one. Expansions created for "derive containers" (see one of the next commits for the description) also didn't get expansion info. --- src/librustc/ich/impls_syntax.rs | 1 + src/librustc/lint/mod.rs | 2 +- src/libsyntax/ext/expand.rs | 14 ++++++++++++-- src/libsyntax_pos/hygiene.rs | 20 +++++++++++++++++--- src/libsyntax_pos/lib.rs | 3 ++- 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 69e8c3550196..e0e7988a744c 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -408,6 +408,7 @@ impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo { }); impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnKind { + Root, Macro(kind, descr), Desugaring(kind) }); diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 3c8b0041a984..e76c24932008 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -885,7 +885,7 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool { }; match info.kind { - ExpnKind::Desugaring(DesugaringKind::ForLoop) => false, + ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false, ExpnKind::Desugaring(_) => true, // well, it's "external" ExpnKind::Macro(MacroKind::Bang, _) => { if info.def_site.is_dummy() { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 39a8a7af2a30..9a6252779e0c 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -5,7 +5,7 @@ use crate::source_map::{dummy_spanned, respan}; use crate::config::StripUnconfigured; use crate::ext::base::*; use crate::ext::derive::{add_derived_markers, collect_derives}; -use crate::ext::hygiene::{Mark, SyntaxContext}; +use crate::ext::hygiene::{Mark, SyntaxContext, ExpnInfo, ExpnKind}; use crate::ext::placeholders::{placeholder, PlaceholderExpander}; use crate::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err}; use crate::mut_visit::*; @@ -847,7 +847,17 @@ struct InvocationCollector<'a, 'b> { impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment { - let mark = Mark::fresh(self.cx.current_expansion.mark, None); + // Expansion info for all the collected invocations is set upon their resolution, + // with exception of the "derive container" case which is not resolved and can get + // its expansion info immediately. + let expn_info = match &kind { + InvocationKind::Attr { attr: None, item, .. } => Some(ExpnInfo::default( + ExpnKind::Macro(MacroKind::Attr, sym::derive), + item.span(), self.cx.parse_sess.edition, + )), + _ => None, + }; + let mark = Mark::fresh(self.cx.current_expansion.mark, expn_info); self.invocations.push(Invocation { kind, fragment_kind, diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index b72da042d046..5df144392309 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -59,6 +59,9 @@ pub struct Mark(u32); #[derive(Debug)] struct MarkData { parent: Mark, + /// Each mark should have an associated expansion info, but sometimes there's a delay between + /// creation of a mark and obtaining its info (e.g. macros are collected first and then + /// resolved later), so we use an `Option` here. expn_info: Option, } @@ -155,11 +158,11 @@ crate struct HygieneData { } impl HygieneData { - crate fn new() -> Self { + crate fn new(edition: Edition) -> Self { HygieneData { marks: vec![MarkData { parent: Mark::root(), - expn_info: None, + expn_info: Some(ExpnInfo::default(ExpnKind::Root, DUMMY_SP, edition)), }], syntax_contexts: vec![SyntaxContextData { outer_mark: Mark::root(), @@ -183,7 +186,15 @@ impl HygieneData { } fn expn_info(&self, mark: Mark) -> Option<&ExpnInfo> { - self.marks[mark.0 as usize].expn_info.as_ref() + if mark != Mark::root() { + Some(self.marks[mark.0 as usize].expn_info.as_ref() + .expect("no expansion info for a mark")) + } else { + // FIXME: Some code relies on `expn_info().is_none()` meaning "no expansion". + // Introduce a method for checking for "no expansion" instead and always return + // `ExpnInfo` from this function instead of the `Option`. + None + } } fn is_descendant_of(&self, mut mark: Mark, ancestor: Mark) -> bool { @@ -670,6 +681,8 @@ impl ExpnInfo { /// Expansion kind. #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub enum ExpnKind { + /// No expansion, aka root expansion. Only `Mark::root()` has this kind. + Root, /// Expansion produced by a macro. /// FIXME: Some code injected by the compiler before HIR lowering also gets this kind. Macro(MacroKind, Symbol), @@ -680,6 +693,7 @@ pub enum ExpnKind { impl ExpnKind { pub fn descr(&self) -> Symbol { match *self { + ExpnKind::Root => kw::PathRoot, ExpnKind::Macro(_, descr) => descr, ExpnKind::Desugaring(kind) => Symbol::intern(kind.descr()), } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 9258b71518ff..5ccfe5f0b8b1 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -60,7 +60,7 @@ impl Globals { Globals { symbol_interner: Lock::new(symbol::Interner::fresh()), span_interner: Lock::new(span_encoding::SpanInterner::default()), - hygiene_data: Lock::new(hygiene::HygieneData::new()), + hygiene_data: Lock::new(hygiene::HygieneData::new(edition)), edition, } } @@ -442,6 +442,7 @@ impl Span { // Don't print recursive invocations. if !info.call_site.source_equal(&prev_span) { let (pre, post) = match info.kind { + ExpnKind::Root => break, ExpnKind::Desugaring(..) => ("desugaring of ", ""), ExpnKind::Macro(macro_kind, _) => match macro_kind { MacroKind::Bang => ("", "!"),