]> git.lizzy.rs Git - rust.git/commitdiff
hygiene: Introduce a helper method for creating new expansions
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Sat, 6 Jul 2019 18:02:45 +0000 (21:02 +0300)
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Wed, 10 Jul 2019 21:12:57 +0000 (00:12 +0300)
Creating a fresh expansion and immediately generating a span from it is the most common scenario.

Also avoid allocating `allow_internal_unstable` lists for derive markers repeatedly.
And rename `ExpnInfo::with_unstable` to `ExpnInfo::allow_unstable`, seems to be a better fitting name.

12 files changed:
src/librustc/hir/lowering.rs
src/librustc/ty/query/on_disk_cache.rs
src/librustc_allocator/expand.rs
src/librustc_resolve/macros.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/derive.rs
src/libsyntax/ext/expand.rs
src/libsyntax/std_inject.rs
src/libsyntax/test.rs
src/libsyntax_ext/proc_macro_decls.rs
src/libsyntax_pos/hygiene.rs
src/libsyntax_pos/symbol.rs

index c44fd30be850a991af358c45de4d1a8124969347..7e7bb5f61a3241ad91cf53000dec3ff92a46f718 100644 (file)
@@ -60,7 +60,7 @@
 use syntax::ast;
 use syntax::ast::*;
 use syntax::errors;
-use syntax::ext::hygiene::{Mark, SyntaxContext};
+use syntax::ext::hygiene::Mark;
 use syntax::print::pprust;
 use syntax::source_map::{respan, ExpnInfo, ExpnKind, DesugaringKind, Spanned};
 use syntax::std_inject;
@@ -875,13 +875,11 @@ fn mark_span_with_reason(
         span: Span,
         allow_internal_unstable: Option<Lrc<[Symbol]>>,
     ) -> Span {
-        let mark = Mark::fresh(Mark::root());
-        mark.set_expn_info(ExpnInfo {
+        span.fresh_expansion(Mark::root(), ExpnInfo {
             def_site: span,
             allow_internal_unstable,
             ..ExpnInfo::default(ExpnKind::Desugaring(reason), span, self.sess.edition())
-        });
-        span.with_ctxt(SyntaxContext::empty().apply_mark(mark))
+        })
     }
 
     fn with_anonymous_lifetime_mode<R>(
index 56c9474170cad0ca533675f6d853240bcc404dd2..d0be13a711117c9f576b6d40e3d19806bc8af524 100644 (file)
@@ -588,41 +588,40 @@ fn specialized_decode(&mut self) -> Result<Span, Self::Error> {
 
         let expn_info_tag = u8::decode(self)?;
 
-        let ctxt = match expn_info_tag {
+        // FIXME(mw): This method does not restore `MarkData::parent` or
+        // `SyntaxContextData::prev_ctxt` or `SyntaxContextData::opaque`. These things
+        // don't seem to be used after HIR lowering, so everything should be fine
+        // as long as incremental compilation does not kick in before that.
+        let location = || Span::new(lo, hi, SyntaxContext::empty());
+        let recover_from_expn_info = |this: &Self, expn_info, pos| {
+            let span = location().fresh_expansion(Mark::root(), expn_info);
+            this.synthetic_expansion_infos.borrow_mut().insert(pos, span.ctxt());
+            span
+        };
+        Ok(match expn_info_tag {
             TAG_NO_EXPANSION_INFO => {
-                SyntaxContext::empty()
+                location()
             }
             TAG_EXPANSION_INFO_INLINE => {
-                let pos = AbsoluteBytePos::new(self.opaque.position());
-                let expn_info: ExpnInfo = Decodable::decode(self)?;
-                let ctxt = SyntaxContext::allocate_directly(expn_info);
-                self.synthetic_expansion_infos.borrow_mut().insert(pos, ctxt);
-                ctxt
+                let expn_info = Decodable::decode(self)?;
+                recover_from_expn_info(
+                    self, expn_info, AbsoluteBytePos::new(self.opaque.position())
+                )
             }
             TAG_EXPANSION_INFO_SHORTHAND => {
                 let pos = AbsoluteBytePos::decode(self)?;
-                let cached_ctxt = self.synthetic_expansion_infos
-                                      .borrow()
-                                      .get(&pos)
-                                      .cloned();
-
-                if let Some(ctxt) = cached_ctxt {
-                    ctxt
+                if let Some(cached_ctxt) = self.synthetic_expansion_infos.borrow().get(&pos) {
+                    Span::new(lo, hi, *cached_ctxt)
                 } else {
-                    let expn_info = self.with_position(pos.to_usize(), |this| {
-                         ExpnInfo::decode(this)
-                    })?;
-                    let ctxt = SyntaxContext::allocate_directly(expn_info);
-                    self.synthetic_expansion_infos.borrow_mut().insert(pos, ctxt);
-                    ctxt
+                    let expn_info =
+                        self.with_position(pos.to_usize(), |this| ExpnInfo::decode(this))?;
+                    recover_from_expn_info(self, expn_info, pos)
                 }
             }
             _ => {
                 unreachable!()
             }
-        };
-
-        Ok(Span::new(lo, hi, ctxt))
+        })
     }
 }
 
index d0eefbb11799fb8e886cbb8183964ef41336eeb9..9803ee99f1a47714f4412fb70ded9142bd574b12 100644 (file)
@@ -14,7 +14,7 @@
         base::{ExtCtxt, MacroKind, Resolver},
         build::AstBuilder,
         expand::ExpansionConfig,
-        hygiene::{Mark, SyntaxContext},
+        hygiene::Mark,
     },
     mut_visit::{self, MutVisitor},
     parse::ParseSess,
@@ -84,16 +84,12 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> {
         }
         self.found = true;
 
-        // Create a fresh Mark for the new macro expansion we are about to do
-        let mark = Mark::fresh(Mark::root());
-        mark.set_expn_info(ExpnInfo::with_unstable(
+        // Create a new expansion for the generated allocator code.
+        let span = item.span.fresh_expansion(Mark::root(), ExpnInfo::allow_unstable(
             ExpnKind::Macro(MacroKind::Attr, sym::global_allocator), item.span, self.sess.edition,
-            &[sym::rustc_attrs],
+            [sym::rustc_attrs][..].into(),
         ));
 
-        // Tie the span to the macro expansion info we just created
-        let span = item.span.with_ctxt(SyntaxContext::empty().apply_mark(mark));
-
         // Create an expansion config
         let ecfg = ExpansionConfig::default(self.crate_name.take().unwrap());
 
index 7ad54d572f4e8b22a738bc8e2c7d85307e4fb0d2..6f276e04a5a39df3bd30fcd07d14045fd7deedd3 100644 (file)
@@ -17,7 +17,7 @@
 use syntax::ext::base::{self, Indeterminate};
 use syntax::ext::base::{MacroKind, SyntaxExtension};
 use syntax::ext::expand::{AstFragment, Invocation, InvocationKind};
-use syntax::ext::hygiene::{self, Mark};
+use syntax::ext::hygiene::{self, Mark, ExpnInfo, ExpnKind};
 use syntax::ext::tt::macro_rules;
 use syntax::feature_gate::{feature_err, emit_feature_err, is_builtin_attr_name};
 use syntax::feature_gate::{AttributeGate, GateIssue, Stability, BUILTIN_ATTRIBUTES};
@@ -148,7 +148,10 @@ fn next_node_id(&mut self) -> ast::NodeId {
     }
 
     fn get_module_scope(&mut self, id: ast::NodeId) -> Mark {
-        let mark = Mark::fresh(Mark::root());
+        let span = DUMMY_SP.fresh_expansion(Mark::root(), ExpnInfo::default(
+            ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, self.session.edition()
+        ));
+        let mark = span.ctxt().outer();
         let module = self.module_map[&self.definitions.local_def_id(id)];
         self.definitions.set_invocation_parent(mark, module.def_id().unwrap().index);
         self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData {
index cb4edee30cdbff73d221a5b5a4c7f9410d1c1226..37d5885db60c3c3d81b649b72df15261c6902cc1 100644 (file)
@@ -721,6 +721,7 @@ pub struct ExtCtxt<'a> {
     pub resolver: &'a mut dyn Resolver,
     pub current_expansion: ExpansionData,
     pub expansions: FxHashMap<Span, Vec<String>>,
+    pub allow_derive_markers: Lrc<[Symbol]>,
 }
 
 impl<'a> ExtCtxt<'a> {
@@ -740,6 +741,7 @@ pub fn new(parse_sess: &'a parse::ParseSess,
                 directory_ownership: DirectoryOwnership::Owned { relative: None },
             },
             expansions: FxHashMap::default(),
+            allow_derive_markers: [sym::rustc_attrs, sym::structural_match][..].into(),
         }
     }
 
index 11c1fceb7e752876b172ef44bbd2e50d5ee7d2b4..1c15deab37377fb5391adbcfcd5d1ebcfa486463 100644 (file)
@@ -8,7 +8,6 @@
 use crate::errors::Applicability;
 
 use syntax_pos::Span;
-use syntax_pos::hygiene::{Mark, SyntaxContext};
 use rustc_data_structures::fx::FxHashSet;
 
 pub fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
@@ -55,13 +54,11 @@ pub fn add_derived_markers<T>(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::P
         names.insert(unwrap_or!(path.segments.get(0), continue).ident.name);
     }
 
-    let mark = Mark::fresh(cx.current_expansion.mark);
-    mark.set_expn_info(ExpnInfo::with_unstable(
+    let span = span.fresh_expansion(cx.current_expansion.mark, ExpnInfo::allow_unstable(
         ExpnKind::Macro(MacroKind::Derive, Symbol::intern(&pretty_name)), span,
-        cx.parse_sess.edition, &[sym::rustc_attrs, sym::structural_match],
+        cx.parse_sess.edition, cx.allow_derive_markers.clone(),
     ));
 
-    let span = span.with_ctxt(SyntaxContext::empty().apply_mark(mark));
     item.visit_attrs(|attrs| {
         if names.contains(&sym::Eq) && names.contains(&sym::PartialEq) {
             let meta = cx.meta_word(span, sym::structural_match);
index 2349382eb5e9bdaa9f2c30f72f69e4f65f43664b..39a8a7af2a3017ea212f1b3a484e5d52cc55dbd2 100644 (file)
@@ -362,7 +362,7 @@ fn expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment {
                 derives.reserve(traits.len());
                 invocations.reserve(traits.len());
                 for path in traits {
-                    let mark = Mark::fresh(self.cx.current_expansion.mark);
+                    let mark = Mark::fresh(self.cx.current_expansion.mark, None);
                     derives.push(mark);
                     invocations.push(Invocation {
                         kind: InvocationKind::Derive {
@@ -847,7 +847,7 @@ 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);
+        let mark = Mark::fresh(self.cx.current_expansion.mark, None);
         self.invocations.push(Invocation {
             kind,
             fragment_kind,
index 81f9ff9b6613b196bbc2789474310b0076298df0..d86b76f71eca7d155ae79f701555c6a091a5fda1 100644 (file)
@@ -1,7 +1,7 @@
 use crate::ast;
 use crate::attr;
 use crate::edition::Edition;
-use crate::ext::hygiene::{Mark, SyntaxContext, MacroKind};
+use crate::ext::hygiene::{Mark, MacroKind};
 use crate::symbol::{Ident, Symbol, kw, sym};
 use crate::source_map::{ExpnInfo, ExpnKind, dummy_spanned, respan};
 use crate::ptr::P;
@@ -9,19 +9,7 @@
 
 use std::cell::Cell;
 use std::iter;
-use syntax_pos::{DUMMY_SP, Span};
-
-/// Craft a span that will be ignored by the stability lint's
-/// call to source_map's `is_internal` check.
-/// The expanded code uses the unstable `#[prelude_import]` attribute.
-fn ignored_span(sp: Span, edition: Edition) -> Span {
-    let mark = Mark::fresh(Mark::root());
-    mark.set_expn_info(ExpnInfo::with_unstable(
-        ExpnKind::Macro(MacroKind::Attr, Symbol::intern("std_inject")), sp, edition,
-        &[sym::prelude_import],
-    ));
-    sp.with_ctxt(SyntaxContext::empty().apply_mark(mark))
-}
+use syntax_pos::DUMMY_SP;
 
 pub fn injected_crate_name() -> Option<&'static str> {
     INJECTED_CRATE_NAME.with(|name| name.get())
@@ -87,7 +75,11 @@ pub fn maybe_inject_crates_ref(
 
     INJECTED_CRATE_NAME.with(|opt_name| opt_name.set(Some(name)));
 
-    let span = ignored_span(DUMMY_SP, edition);
+    let span = DUMMY_SP.fresh_expansion(Mark::root(), ExpnInfo::allow_unstable(
+        ExpnKind::Macro(MacroKind::Attr, sym::std_inject), DUMMY_SP, edition,
+        [sym::prelude_import][..].into(),
+    ));
+
     krate.module.items.insert(0, P(ast::Item {
         attrs: vec![ast::Attribute {
             style: ast::AttrStyle::Outer,
index 7ec7bb6ff458f2873c4e18b2bf01e626168b1611..799d64a9962371070fc5ba68223ce07ed1714388 100644 (file)
@@ -43,7 +43,6 @@ struct TestCtxt<'a> {
     test_cases: Vec<Test>,
     reexport_test_harness_main: Option<Symbol>,
     is_libtest: bool,
-    ctxt: SyntaxContext,
     features: &'a Features,
     test_runner: Option<ast::Path>,
 
@@ -259,8 +258,6 @@ fn generate_test_harness(sess: &ParseSess,
     let mut cleaner = EntryPointCleaner { depth: 0 };
     cleaner.visit_crate(krate);
 
-    let mark = Mark::fresh(Mark::root());
-
     let mut econfig = ExpansionConfig::default("test".to_string());
     econfig.features = Some(features);
 
@@ -274,16 +271,10 @@ fn generate_test_harness(sess: &ParseSess,
         is_libtest: attr::find_crate_name(&krate.attrs)
             .map(|s| s == sym::test).unwrap_or(false),
         toplevel_reexport: None,
-        ctxt: SyntaxContext::empty().apply_mark(mark),
         features,
         test_runner
     };
 
-    mark.set_expn_info(ExpnInfo::with_unstable(
-        ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, sess.edition,
-        &[sym::main, sym::test, sym::rustc_attrs],
-    ));
-
     TestHarnessGenerator {
         cx,
         tests: Vec::new(),
@@ -291,13 +282,6 @@ fn generate_test_harness(sess: &ParseSess,
     }.visit_crate(krate);
 }
 
-/// Craft a span that will be ignored by the stability lint's
-/// call to source_map's `is_internal` check.
-/// The expanded code calls some unstable functions in the test crate.
-fn ignored_span(cx: &TestCtxt<'_>, sp: Span) -> Span {
-    sp.with_ctxt(cx.ctxt)
-}
-
 enum HasTestSignature {
     Yes,
     No(BadTestSignature),
@@ -314,12 +298,15 @@ enum BadTestSignature {
 /// Creates a function item for use as the main function of a test build.
 /// This function will call the `test_runner` as specified by the crate attribute
 fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
-    // Writing this out by hand with 'ignored_span':
+    // Writing this out by hand:
     //        pub fn main() {
     //            #![main]
     //            test::test_main_static(&[..tests]);
     //        }
-    let sp = ignored_span(cx, DUMMY_SP);
+    let sp = DUMMY_SP.fresh_expansion(Mark::root(), ExpnInfo::allow_unstable(
+        ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, cx.ext_cx.parse_sess.edition,
+        [sym::main, sym::test, sym::rustc_attrs][..].into(),
+    ));
     let ecx = &cx.ext_cx;
     let test_id = Ident::with_empty_ctxt(sym::test);
 
index 0733a8ec95c71b2d45d69a9493ad315c7654eea6..2f78644dff2aa89e2673fcce79f0a3d4e5c069e9 100644 (file)
@@ -346,12 +346,10 @@ fn mk_decls(
     custom_attrs: &[ProcMacroDef],
     custom_macros: &[ProcMacroDef],
 ) -> P<ast::Item> {
-    let mark = Mark::fresh(Mark::root());
-    mark.set_expn_info(ExpnInfo::with_unstable(
+    let span = DUMMY_SP.fresh_expansion(Mark::root(), ExpnInfo::allow_unstable(
         ExpnKind::Macro(MacroKind::Attr, sym::proc_macro), DUMMY_SP, cx.parse_sess.edition,
-        &[sym::rustc_attrs, Symbol::intern("proc_macro_internals")],
+        [sym::rustc_attrs, sym::proc_macro_internals][..].into(),
     ));
-    let span = DUMMY_SP.apply_mark(mark);
 
     let hidden = cx.meta_list_item_word(span, sym::hidden);
     let doc = cx.meta_list(span, sym::doc, vec![hidden]);
index ba2b2b7a2dd1138fb86310fdb41ced36bf261b3d..f060bf356f6d723d84e630987213888bf6700ea8 100644 (file)
@@ -82,11 +82,8 @@ pub enum Transparency {
 }
 
 impl Mark {
-    pub fn fresh(parent: Mark) -> Self {
-        HygieneData::with(|data| {
-            data.marks.push(MarkData { parent, expn_info: None });
-            Mark(data.marks.len() as u32 - 1)
-        })
+    pub fn fresh(parent: Mark, expn_info: Option<ExpnInfo>) -> Self {
+        HygieneData::with(|data| data.fresh_mark(parent, expn_info))
     }
 
     /// The mark of the theoretical expansion that generates freshly parsed, unexpanded AST.
@@ -180,6 +177,11 @@ fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
         GLOBALS.with(|globals| f(&mut *globals.hygiene_data.borrow_mut()))
     }
 
+    fn fresh_mark(&mut self, parent: Mark, expn_info: Option<ExpnInfo>) -> Mark {
+        self.marks.push(MarkData { parent, expn_info });
+        Mark(self.marks.len() as u32 - 1)
+    }
+
     fn expn_info(&self, mark: Mark) -> Option<&ExpnInfo> {
         self.marks[mark.0 as usize].expn_info.as_ref()
     }
@@ -396,33 +398,6 @@ pub const fn empty() -> Self {
         SyntaxContext(raw)
     }
 
-    // Allocate a new SyntaxContext with the given ExpnInfo. This is used when
-    // deserializing Spans from the incr. comp. cache.
-    // FIXME(mw): This method does not restore MarkData::parent or
-    // SyntaxContextData::prev_ctxt or SyntaxContextData::opaque. These things
-    // don't seem to be used after HIR lowering, so everything should be fine
-    // as long as incremental compilation does not kick in before that.
-    pub fn allocate_directly(expansion_info: ExpnInfo) -> Self {
-        HygieneData::with(|data| {
-            data.marks.push(MarkData {
-                parent: Mark::root(),
-                expn_info: Some(expansion_info),
-            });
-
-            let mark = Mark(data.marks.len() as u32 - 1);
-
-            data.syntax_contexts.push(SyntaxContextData {
-                outer_mark: mark,
-                transparency: Transparency::SemiTransparent,
-                prev_ctxt: SyntaxContext::empty(),
-                opaque: SyntaxContext::empty(),
-                opaque_and_semitransparent: SyntaxContext::empty(),
-                dollar_crate_name: kw::DollarCrate,
-            });
-            SyntaxContext(data.syntax_contexts.len() as u32 - 1)
-        })
-    }
-
     /// Extend a syntax context with a given mark and default transparency for that mark.
     pub fn apply_mark(self, mark: Mark) -> SyntaxContext {
         HygieneData::with(|data| data.apply_mark(self, mark))
@@ -615,6 +590,20 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
+impl Span {
+    /// Creates a fresh expansion with given properties.
+    /// Expansions are normally created by macros, but in some cases expansions are created for
+    /// other compiler-generated code to set per-span properties like allowed unstable features.
+    /// The returned span belongs to the created expansion and has the new properties,
+    /// but its location is inherited from the current span.
+    pub fn fresh_expansion(self, parent: Mark, expn_info: ExpnInfo) -> Span {
+        HygieneData::with(|data| {
+            let mark = data.fresh_mark(parent, Some(expn_info));
+            self.with_ctxt(data.apply_mark(SyntaxContext::empty(), mark))
+        })
+    }
+}
+
 /// A subset of properties from both macro definition and macro call available through global data.
 /// Avoid using this if you have access to the original definition or call structures.
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
@@ -669,10 +658,10 @@ pub fn default(kind: ExpnKind, call_site: Span, edition: Edition) -> ExpnInfo {
         }
     }
 
-    pub fn with_unstable(kind: ExpnKind, call_site: Span, edition: Edition,
-                         allow_internal_unstable: &[Symbol]) -> ExpnInfo {
+    pub fn allow_unstable(kind: ExpnKind, call_site: Span, edition: Edition,
+                          allow_internal_unstable: Lrc<[Symbol]>) -> ExpnInfo {
         ExpnInfo {
-            allow_internal_unstable: Some(allow_internal_unstable.into()),
+            allow_internal_unstable: Some(allow_internal_unstable),
             ..ExpnInfo::default(kind, call_site, edition)
         }
     }
index 89fcf3b1f8f190845213d7f55d709e50c5f22498..581fd47c4b3b582f8668065373f0cde443e762c4 100644 (file)
         proc_macro_expr,
         proc_macro_gen,
         proc_macro_hygiene,
+        proc_macro_internals,
         proc_macro_mod,
         proc_macro_non_items,
         proc_macro_path_invoc,
         static_nobundle,
         static_recursion,
         std,
+        std_inject,
         str,
         stringify,
         stmt,