Skip to content
Permalink
Browse files

hygiene: Introduce a helper method for creating new expansions

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.
  • Loading branch information...
petrochenkov committed Jul 6, 2019
1 parent d1949b1 commit 99c7432896bbfdab1f7f70f8d763cab5f3efe64a
@@ -60,7 +60,7 @@ use syntax::attr;
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 @@ impl<'a> LoweringContext<'a> {
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>(
@@ -588,41 +588,40 @@ impl<'a, 'tcx> SpecializedDecoder<Span> for CacheDecoder<'a, 'tcx> {

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))
})
}
}

@@ -14,7 +14,7 @@ use syntax::{
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());

@@ -17,7 +17,7 @@ use syntax::errors::DiagnosticBuilder;
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 @@ impl<'a> base::Resolver for Resolver<'a> {
}

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 {
@@ -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 @@ impl<'a> ExtCtxt<'a> {
directory_ownership: DirectoryOwnership::Owned { relative: None },
},
expansions: FxHashMap::default(),
allow_derive_markers: [sym::rustc_attrs, sym::structural_match][..].into(),
}
}

@@ -8,7 +8,6 @@ use crate::symbol::{Symbol, sym};
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);
@@ -362,7 +362,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
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,
@@ -1,27 +1,15 @@
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;
use crate::tokenstream::TokenStream;

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,
@@ -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,30 +271,17 @@ 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(),
tested_submods: Vec::new(),
}.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);

@@ -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]);

0 comments on commit 99c7432

Please sign in to comment.
You can’t perform that action at this time.