Audit uses of apply_mark in built-in macros

Replace them with equivalents of `Span::{def_site,call_site}` from proc macro API.
The new API is much less error prone and doesn't rely on macros having default transparency.
This commit is contained in:
Vadim Petrochenkov 2019-08-21 21:28:22 +03:00
parent 760226733e
commit 0fb01d219c
19 changed files with 56 additions and 41 deletions

View File

@ -3,7 +3,7 @@ use crate::attr::{HasAttrs, Stability, Deprecation};
use crate::source_map::SourceMap;
use crate::edition::Edition;
use crate::ext::expand::{self, AstFragment, Invocation};
use crate::ext::hygiene::{ExpnId, SyntaxContext, Transparency};
use crate::ext::hygiene::{ExpnId, Transparency};
use crate::mut_visit::{self, MutVisitor};
use crate::parse::{self, parser, DirectoryOwnership};
use crate::parse::token;
@ -760,23 +760,39 @@ impl<'a> ExtCtxt<'a> {
pub fn call_site(&self) -> Span {
self.current_expansion.id.expn_data().call_site
}
pub fn backtrace(&self) -> SyntaxContext {
SyntaxContext::root().apply_mark(self.current_expansion.id)
/// Equivalent of `Span::def_site` from the proc macro API,
/// except that the location is taken from the span passed as an argument.
pub fn with_def_site_ctxt(&self, span: Span) -> Span {
span.with_ctxt_from_mark(self.current_expansion.id, Transparency::Opaque)
}
/// Equivalent of `Span::call_site` from the proc macro API,
/// except that the location is taken from the span passed as an argument.
pub fn with_call_site_ctxt(&self, span: Span) -> Span {
span.with_ctxt_from_mark(self.current_expansion.id, Transparency::Transparent)
}
/// Span with a context reproducing `macro_rules` hygiene (hygienic locals, unhygienic items).
/// FIXME: This should be eventually replaced either with `with_def_site_ctxt` (preferably),
/// or with `with_call_site_ctxt` (where necessary).
pub fn with_legacy_ctxt(&self, span: Span) -> Span {
span.with_ctxt_from_mark(self.current_expansion.id, Transparency::SemiTransparent)
}
/// Returns span for the macro which originally caused the current expansion to happen.
///
/// Stops backtracing at include! boundary.
pub fn expansion_cause(&self) -> Option<Span> {
let mut ctxt = self.backtrace();
let mut expn_id = self.current_expansion.id;
let mut last_macro = None;
loop {
let expn_data = ctxt.outer_expn_data();
let expn_data = expn_id.expn_data();
// Stop going up the backtrace once include! is encountered
if expn_data.is_root() || expn_data.kind.descr() == sym::include {
break;
}
ctxt = expn_data.call_site.ctxt();
expn_id = expn_data.call_site.ctxt().outer_expn();
last_macro = Some(expn_data.call_site);
}
last_macro
@ -865,7 +881,7 @@ impl<'a> ExtCtxt<'a> {
ast::Ident::from_str(st)
}
pub fn std_path(&self, components: &[Symbol]) -> Vec<ast::Ident> {
let def_site = DUMMY_SP.apply_mark(self.current_expansion.id);
let def_site = self.with_def_site_ctxt(DUMMY_SP);
iter::once(Ident::new(kw::DollarCrate, def_site))
.chain(components.iter().map(|&s| Ident::with_dummy_span(s)))
.collect()

View File

@ -565,7 +565,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
return fragment_kind.dummy(span);
}
let meta = ast::MetaItem { node: ast::MetaItemKind::Word, span, path };
let span = span.with_ctxt(self.cx.backtrace());
let items = expander.expand(self.cx, span, &meta, item);
fragment_kind.expect_from_annotatables(items)
}

View File

@ -7,7 +7,6 @@ use crate::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint}
use errors::{Diagnostic, DiagnosticBuilder};
use rustc_data_structures::sync::Lrc;
use syntax_pos::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
use syntax_pos::hygiene::{SyntaxContext, Transparency};
use syntax_pos::symbol::{kw, sym, Symbol};
use proc_macro::{Delimiter, Level, LineColumn, Spacing};
@ -363,16 +362,10 @@ impl<'a> Rustc<'a> {
pub fn new(cx: &'a ExtCtxt<'_>) -> Self {
// No way to determine def location for a proc macro right now, so use call location.
let location = cx.current_expansion.id.expn_data().call_site;
let to_span = |transparency| {
location.with_ctxt(
SyntaxContext::root()
.apply_mark_with_transparency(cx.current_expansion.id, transparency),
)
};
Rustc {
sess: cx.parse_sess,
def_site: to_span(Transparency::Opaque),
call_site: to_span(Transparency::Transparent),
def_site: cx.with_def_site_ctxt(location),
call_site: cx.with_call_site_ctxt(location),
}
}

View File

@ -63,7 +63,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt<'_>,
MacEager::expr(P(ast::Expr {
id: ast::DUMMY_NODE_ID,
node: ast::ExprKind::InlineAsm(P(inline_asm)),
span: sp.with_ctxt(cx.backtrace()),
span: cx.with_legacy_ctxt(sp),
attrs: ThinVec::new(),
}))
}

View File

@ -23,7 +23,7 @@ pub fn expand_assert<'cx>(
}
};
let sp = sp.apply_mark(cx.current_expansion.id);
let sp = cx.with_legacy_ctxt(sp);
let panic_call = Mac {
path: Path::from_ident(Ident::new(sym::panic, sp)),
tts: custom_message.unwrap_or_else(|| {

View File

@ -16,7 +16,7 @@ pub fn expand_cfg(
sp: Span,
tts: &[tokenstream::TokenTree],
) -> Box<dyn base::MacResult + 'static> {
let sp = sp.apply_mark(cx.current_expansion.id);
let sp = cx.with_legacy_ctxt(sp);
match parse_cfg(cx, sp, tts) {
Ok(cfg) => {

View File

@ -59,6 +59,6 @@ pub fn expand_syntax_ext(
} else if has_errors {
return DummyResult::any(sp);
}
let sp = sp.apply_mark(cx.current_expansion.id);
let sp = cx.with_legacy_ctxt(sp);
base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator)))
}

View File

@ -39,7 +39,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt<'_>,
}
}
let ident = ast::Ident::new(Symbol::intern(&res_str), sp.apply_mark(cx.current_expansion.id));
let ident = ast::Ident::new(Symbol::intern(&res_str), cx.with_legacy_ctxt(sp));
struct ConcatIdentsResult { ident: ast::Ident }

View File

@ -112,7 +112,7 @@ fn cs_clone_shallow(name: &str,
ty: P<ast::Ty>, span: Span, helper_name: &str) {
// Generate statement `let _: helper_name<ty>;`,
// set the expn ID so we can use the unstable struct.
let span = span.with_ctxt(cx.backtrace());
let span = cx.with_def_site_ctxt(span);
let assert_path = cx.path_all(span, true,
cx.std_path(&[sym::clone, Symbol::intern(helper_name)]),
vec![GenericArg::Type(ty)], vec![]);

View File

@ -53,7 +53,7 @@ fn cs_total_eq_assert(cx: &mut ExtCtxt<'_>,
ty: P<ast::Ty>, span: Span, helper_name: &str) {
// Generate statement `let _: helper_name<ty>;`,
// set the expn ID so we can use the unstable struct.
let span = span.with_ctxt(cx.backtrace());
let span = cx.with_def_site_ctxt(span);
let assert_path = cx.path_all(span, true,
cx.std_path(&[sym::cmp, Symbol::intern(helper_name)]),
vec![GenericArg::Type(ty)], vec![]);

View File

@ -60,7 +60,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
};
// We want to make sure we have the ctxt set so that we can use unstable methods
let span = span.with_ctxt(cx.backtrace());
let span = cx.with_def_site_ctxt(span);
let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked));
let builder = Ident::from_str_and_span("debug_trait_builder", span);
let builder_expr = cx.expr_ident(span, builder.clone());

View File

@ -85,7 +85,7 @@ impl<'a> Path<'a> {
PathKind::Global => cx.path_all(span, true, idents, params, Vec::new()),
PathKind::Local => cx.path_all(span, false, idents, params, Vec::new()),
PathKind::Std => {
let def_site = DUMMY_SP.apply_mark(cx.current_expansion.id);
let def_site = cx.with_def_site_ctxt(DUMMY_SP);
idents.insert(0, Ident::new(kw::DollarCrate, def_site));
cx.path_all(span, false, idents, params, Vec::new())
}

View File

@ -48,6 +48,9 @@ impl MultiItemModifier for BuiltinDerive {
meta_item: &MetaItem,
item: Annotatable)
-> Vec<Annotatable> {
// FIXME: Built-in derives often forget to give spans contexts,
// so we are doing it here in a centralized way.
let span = ecx.with_def_site_ctxt(span);
let mut items = Vec::new();
(self.0)(ecx, span, meta_item, &item, &mut |a| items.push(a));
items
@ -60,7 +63,7 @@ fn call_intrinsic(cx: &ExtCtxt<'_>,
intrinsic: &str,
args: Vec<P<ast::Expr>>)
-> P<ast::Expr> {
let span = span.with_ctxt(cx.backtrace());
let span = cx.with_def_site_ctxt(span);
let path = cx.std_path(&[sym::intrinsics, Symbol::intern(intrinsic)]);
let call = cx.expr_call_global(span, path, args);

View File

@ -20,7 +20,7 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt<'_>,
Some(v) => v,
};
let sp = sp.apply_mark(cx.current_expansion.id);
let sp = cx.with_legacy_ctxt(sp);
let e = match env::var(&*var.as_str()) {
Err(..) => {
let lt = cx.lifetime(sp, Ident::with_dummy_span(kw::StaticLifetime));

View File

@ -12,7 +12,7 @@ use syntax::parse::token;
use syntax::ptr::P;
use syntax::symbol::{Symbol, sym};
use syntax::tokenstream;
use syntax_pos::{MultiSpan, Span, DUMMY_SP};
use syntax_pos::{MultiSpan, Span};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use std::borrow::Cow;
@ -666,8 +666,7 @@ impl<'a, 'b> Context<'a, 'b> {
// passed to this function.
for (i, e) in self.args.into_iter().enumerate() {
let name = names_pos[i];
let span =
DUMMY_SP.with_ctxt(e.span.ctxt().apply_mark(self.ecx.current_expansion.id));
let span = self.ecx.with_def_site_ctxt(e.span);
pats.push(self.ecx.pat_ident(span, name));
for ref arg_ty in self.arg_unique_types[i].iter() {
locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, name));
@ -745,7 +744,7 @@ impl<'a, 'b> Context<'a, 'b> {
ty: &ArgumentType,
arg: ast::Ident,
) -> P<ast::Expr> {
sp = sp.apply_mark(ecx.current_expansion.id);
sp = ecx.with_def_site_ctxt(sp);
let arg = ecx.expr_ident(sp, arg);
let trait_ = match *ty {
Placeholder(ref tyname) => {
@ -798,7 +797,7 @@ fn expand_format_args_impl<'cx>(
tts: &[tokenstream::TokenTree],
nl: bool,
) -> Box<dyn base::MacResult + 'cx> {
sp = sp.apply_mark(ecx.current_expansion.id);
sp = ecx.with_def_site_ctxt(sp);
match parse_args(ecx, sp, tts) {
Ok((efmt, args, names)) => {
MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names, nl))
@ -842,7 +841,7 @@ pub fn expand_preparsed_format_args(
let arg_unique_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect();
let mut macsp = ecx.call_site();
macsp = macsp.with_ctxt(ecx.backtrace());
macsp = ecx.with_def_site_ctxt(macsp);
let msg = "format argument must be a string literal";
let fmt_sp = efmt.span;

View File

@ -3,7 +3,6 @@ use syntax::ast::{self, Arg, Attribute, Expr, FnHeader, Generics, Ident};
use syntax::attr::check_builtin_macro_attribute;
use syntax::ext::allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS};
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::hygiene::SyntaxContext;
use syntax::ptr::P;
use syntax::symbol::{kw, sym, Symbol};
use syntax_pos::Span;
@ -29,7 +28,7 @@ pub fn expand(
};
// Generate a bunch of new items using the AllocFnFactory
let span = item.span.with_ctxt(SyntaxContext::root().apply_mark(ecx.current_expansion.id));
let span = ecx.with_legacy_ctxt(item.span);
let f = AllocFnFactory {
span,
kind: AllocatorKind::Global,

View File

@ -30,7 +30,7 @@ pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt<'_>,
id: ast::DUMMY_NODE_ID,
node: ast::ItemKind::GlobalAsm(P(global_asm)),
vis: respan(sp.shrink_to_lo(), ast::VisibilityKind::Inherited),
span: sp.with_ctxt(cx.backtrace()),
span: cx.with_legacy_ctxt(sp),
tokens: None,
})])
}

View File

@ -4,7 +4,6 @@
use syntax::ast;
use syntax::attr::{self, check_builtin_macro_attribute};
use syntax::ext::base::*;
use syntax::ext::hygiene::SyntaxContext;
use syntax::print::pprust;
use syntax::source_map::respan;
use syntax::symbol::{Symbol, sym};
@ -29,7 +28,7 @@ pub fn expand_test_case(
if !ecx.ecfg.should_test { return vec![]; }
let sp = attr_sp.with_ctxt(SyntaxContext::root().apply_mark(ecx.current_expansion.id));
let sp = ecx.with_legacy_ctxt(attr_sp);
let mut item = anno_item.expect_item();
item = item.map(|mut item| {
item.vis = respan(item.vis.span, ast::VisibilityKind::Public);
@ -93,8 +92,7 @@ pub fn expand_test_or_bench(
return vec![Annotatable::Item(item)];
}
let ctxt = SyntaxContext::root().apply_mark(cx.current_expansion.id);
let (sp, attr_sp) = (item.span.with_ctxt(ctxt), attr_sp.with_ctxt(ctxt));
let (sp, attr_sp) = (cx.with_legacy_ctxt(item.span), cx.with_legacy_ctxt(attr_sp));
// Gensym "test" so we can extern crate without conflicting with any local names
let test_id = cx.ident_of("test").gensym();

View File

@ -22,6 +22,7 @@ pub mod edition;
use edition::Edition;
pub mod hygiene;
pub use hygiene::{ExpnId, SyntaxContext, ExpnData, ExpnKind, MacroKind, DesugaringKind};
use hygiene::Transparency;
mod span_encoding;
pub use span_encoding::{Span, DUMMY_SP};
@ -512,6 +513,13 @@ impl Span {
span.ctxt)
}
/// Produces a span with the same location as `self` and context produced by a macro with the
/// given ID and transparency, assuming that macro was defined directly and not produced by
/// some other macro (which is the case for built-in and procedural macros).
pub fn with_ctxt_from_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span {
self.with_ctxt(SyntaxContext::root().apply_mark_with_transparency(expn_id, transparency))
}
#[inline]
pub fn apply_mark(self, mark: ExpnId) -> Span {
let span = self.data();