Rollup merge of #63761 - petrochenkov:procattrs, r=eddyb
Propagate spans and attributes from proc macro definitions Thanks to https://github.com/rust-lang/rust/pull/63269 we now have spans and attributes from proc macro definitions available in metadata. However, that PR didn't actually put them into use! This PR finishes that work. Attributes `rustc_macro_transparency`, `allow_internal_unstable`, `allow_internal_unsafe`, `local_inner_macros`, `rustc_builtin_macro`, `stable`, `unstable`, `rustc_deprecated`, `deprecated` now have effect when applied to proc macro definition functions. From those attributes only `deprecated` is both stable and supposed to be used in new code. (`#![staged_api]` still cannot be used in proc macro crates for unrelated reasons though.) `Span::def_site` from the proc macro API now returns the correct location of the proc macro definition. Also, I made a mistake in https://github.com/rust-lang/rust/pull/63269#discussion_r312702919, loaded proc macros didn't actually use the resolver cache. This PR fixes the caching issue, now proc macros go through the `Resolver::macro_map` cache as well. (Also, the first commit turns `proc_macro::quote` into a regular built-in macro to reduce the number of places where `SyntaxExtension`s need to be manually created.)
This commit is contained in:
commit
0da7098116
21 changed files with 310 additions and 164 deletions
|
@ -19,12 +19,15 @@
|
||||||
|
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
|
#![feature(allow_internal_unstable)]
|
||||||
#![feature(const_fn)]
|
#![feature(const_fn)]
|
||||||
|
#![feature(decl_macro)]
|
||||||
#![feature(extern_types)]
|
#![feature(extern_types)]
|
||||||
#![feature(in_band_lifetimes)]
|
#![feature(in_band_lifetimes)]
|
||||||
#![feature(optin_builtin_traits)]
|
#![feature(optin_builtin_traits)]
|
||||||
#![feature(mem_take)]
|
#![feature(mem_take)]
|
||||||
#![feature(non_exhaustive)]
|
#![feature(non_exhaustive)]
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
#![recursion_limit="256"]
|
#![recursion_limit="256"]
|
||||||
|
@ -222,11 +225,10 @@ pub mod token_stream {
|
||||||
///
|
///
|
||||||
/// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term.
|
/// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term.
|
||||||
/// To quote `$` itself, use `$$`.
|
/// To quote `$` itself, use `$$`.
|
||||||
///
|
|
||||||
/// This is a dummy macro, the actual implementation is in `quote::quote`.`
|
|
||||||
#[unstable(feature = "proc_macro_quote", issue = "54722")]
|
#[unstable(feature = "proc_macro_quote", issue = "54722")]
|
||||||
#[macro_export]
|
#[allow_internal_unstable(proc_macro_def_site)]
|
||||||
macro_rules! quote { () => {} }
|
#[cfg_attr(not(bootstrap), rustc_builtin_macro)]
|
||||||
|
pub macro quote ($($t:tt)*) { /* compiler built-in */ }
|
||||||
|
|
||||||
#[unstable(feature = "proc_macro_internals", issue = "27812")]
|
#[unstable(feature = "proc_macro_internals", issue = "27812")]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
|
|
@ -57,9 +57,9 @@ macro_rules! quote {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Quote a `TokenStream` into a `TokenStream`.
|
/// Quote a `TokenStream` into a `TokenStream`.
|
||||||
/// This is the actual `quote!()` proc macro.
|
/// This is the actual implementation of the `quote!()` proc macro.
|
||||||
///
|
///
|
||||||
/// It is manually loaded in `CStore::load_macro_untracked`.
|
/// It is loaded by the compiler in `register_builtin_macros`.
|
||||||
#[unstable(feature = "proc_macro_quote", issue = "54722")]
|
#[unstable(feature = "proc_macro_quote", issue = "54722")]
|
||||||
pub fn quote(stream: TokenStream) -> TokenStream {
|
pub fn quote(stream: TokenStream) -> TokenStream {
|
||||||
if stream.is_empty() {
|
if stream.is_empty() {
|
||||||
|
|
|
@ -95,11 +95,6 @@ pub struct CrateMetadata {
|
||||||
pub raw_proc_macros: Option<&'static [ProcMacro]>,
|
pub raw_proc_macros: Option<&'static [ProcMacro]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FullProcMacro {
|
|
||||||
pub name: ast::Name,
|
|
||||||
pub ext: Lrc<SyntaxExtension>
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CStore {
|
pub struct CStore {
|
||||||
metas: RwLock<IndexVec<CrateNum, Option<Lrc<CrateMetadata>>>>,
|
metas: RwLock<IndexVec<CrateNum, Option<Lrc<CrateMetadata>>>>,
|
||||||
/// Map from NodeId's of local extern crate statements to crate numbers
|
/// Map from NodeId's of local extern crate statements to crate numbers
|
||||||
|
@ -109,7 +104,7 @@ pub struct CStore {
|
||||||
|
|
||||||
pub enum LoadedMacro {
|
pub enum LoadedMacro {
|
||||||
MacroDef(ast::Item),
|
MacroDef(ast::Item),
|
||||||
ProcMacro(Lrc<SyntaxExtension>),
|
ProcMacro(SyntaxExtension),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CStore {
|
impl CStore {
|
||||||
|
|
|
@ -30,11 +30,9 @@ use syntax::ast;
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
use syntax::source_map;
|
use syntax::source_map;
|
||||||
use syntax::edition::Edition;
|
use syntax::edition::Edition;
|
||||||
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
|
|
||||||
use syntax::ext::proc_macro::BangProcMacro;
|
|
||||||
use syntax::parse::source_file_to_stream;
|
use syntax::parse::source_file_to_stream;
|
||||||
use syntax::parse::parser::emit_unclosed_delims;
|
use syntax::parse::parser::emit_unclosed_delims;
|
||||||
use syntax::symbol::{Symbol, sym};
|
use syntax::symbol::Symbol;
|
||||||
use syntax_pos::{Span, FileName};
|
use syntax_pos::{Span, FileName};
|
||||||
use rustc_data_structures::bit_set::BitSet;
|
use rustc_data_structures::bit_set::BitSet;
|
||||||
|
|
||||||
|
@ -436,15 +434,7 @@ impl cstore::CStore {
|
||||||
pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro {
|
pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro {
|
||||||
let data = self.get_crate_data(id.krate);
|
let data = self.get_crate_data(id.krate);
|
||||||
if data.is_proc_macro_crate() {
|
if data.is_proc_macro_crate() {
|
||||||
return LoadedMacro::ProcMacro(data.get_proc_macro(id.index, sess).ext);
|
return LoadedMacro::ProcMacro(data.load_proc_macro(id.index, sess));
|
||||||
} else if data.name == sym::proc_macro && data.item_name(id.index) == sym::quote {
|
|
||||||
let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
|
|
||||||
let kind = SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client }));
|
|
||||||
let ext = SyntaxExtension {
|
|
||||||
allow_internal_unstable: Some([sym::proc_macro_def_site][..].into()),
|
|
||||||
..SyntaxExtension::default(kind, data.root.edition)
|
|
||||||
};
|
|
||||||
return LoadedMacro::ProcMacro(Lrc::new(ext));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let def = data.get_macro(id.index);
|
let def = data.get_macro(id.index);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Decoding metadata from a single crate's metadata
|
// Decoding metadata from a single crate's metadata
|
||||||
|
|
||||||
use crate::cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, ForeignModule, FullProcMacro};
|
use crate::cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary, ForeignModule};
|
||||||
use crate::schema::*;
|
use crate::schema::*;
|
||||||
|
|
||||||
use rustc_data_structures::indexed_vec::IndexVec;
|
use rustc_data_structures::indexed_vec::IndexVec;
|
||||||
|
@ -512,27 +512,8 @@ impl<'a, 'tcx> CrateMetadata {
|
||||||
self.entry(index).span.decode((self, sess))
|
self.entry(index).span.decode((self, sess))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crate fn load_proc_macro(&self, id: DefIndex, sess: &Session) -> SyntaxExtension {
|
||||||
pub fn get_proc_macro(&self, id: DefIndex, sess: &Session) -> FullProcMacro {
|
let (name, kind, helper_attrs) = match *self.raw_proc_macro(id) {
|
||||||
if sess.opts.debugging_opts.dual_proc_macros {
|
|
||||||
let host_lib = self.host_lib.as_ref().unwrap();
|
|
||||||
self.load_proc_macro(
|
|
||||||
&host_lib.metadata.get_root(),
|
|
||||||
id,
|
|
||||||
sess
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
self.load_proc_macro(&self.root, id, sess)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_proc_macro(&self, root: &CrateRoot<'_>,
|
|
||||||
id: DefIndex,
|
|
||||||
sess: &Session)
|
|
||||||
-> FullProcMacro {
|
|
||||||
|
|
||||||
let raw_macro = self.raw_proc_macro(id);
|
|
||||||
let (name, kind, helper_attrs) = match *raw_macro {
|
|
||||||
ProcMacro::CustomDerive { trait_name, attributes, client } => {
|
ProcMacro::CustomDerive { trait_name, attributes, client } => {
|
||||||
let helper_attrs =
|
let helper_attrs =
|
||||||
attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
|
attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
|
||||||
|
@ -551,17 +532,21 @@ impl<'a, 'tcx> CrateMetadata {
|
||||||
name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new()
|
name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new()
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
let edition = if sess.opts.debugging_opts.dual_proc_macros {
|
||||||
|
self.host_lib.as_ref().unwrap().metadata.get_root().edition
|
||||||
|
} else {
|
||||||
|
self.root.edition
|
||||||
|
};
|
||||||
|
|
||||||
let span = self.get_span(id, sess);
|
SyntaxExtension::new(
|
||||||
|
&sess.parse_sess,
|
||||||
FullProcMacro {
|
kind,
|
||||||
name: Symbol::intern(name),
|
self.get_span(id, sess),
|
||||||
ext: Lrc::new(SyntaxExtension {
|
helper_attrs,
|
||||||
span,
|
edition,
|
||||||
helper_attrs,
|
Symbol::intern(name),
|
||||||
..SyntaxExtension::default(kind, root.edition)
|
&self.get_attributes(&self.entry(id), sess),
|
||||||
})
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef {
|
pub fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef {
|
||||||
|
|
|
@ -150,12 +150,12 @@ impl<'a> Resolver<'a> {
|
||||||
return Some(ext.clone());
|
return Some(ext.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let macro_def = match self.cstore.load_macro_untracked(def_id, &self.session) {
|
let ext = Lrc::new(match self.cstore.load_macro_untracked(def_id, &self.session) {
|
||||||
LoadedMacro::MacroDef(macro_def) => macro_def,
|
LoadedMacro::MacroDef(item) =>
|
||||||
LoadedMacro::ProcMacro(ext) => return Some(ext),
|
self.compile_macro(&item, self.cstore.crate_edition_untracked(def_id.krate)),
|
||||||
};
|
LoadedMacro::ProcMacro(ext) => ext,
|
||||||
|
});
|
||||||
|
|
||||||
let ext = self.compile_macro(¯o_def, self.cstore.crate_edition_untracked(def_id.krate));
|
|
||||||
self.macro_map.insert(def_id, ext.clone());
|
self.macro_map.insert(def_id, ext.clone());
|
||||||
Some(ext)
|
Some(ext)
|
||||||
}
|
}
|
||||||
|
@ -1104,7 +1104,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
||||||
let expansion = parent_scope.expansion;
|
let expansion = parent_scope.expansion;
|
||||||
let (ext, ident, span, is_legacy) = match &item.node {
|
let (ext, ident, span, is_legacy) = match &item.node {
|
||||||
ItemKind::MacroDef(def) => {
|
ItemKind::MacroDef(def) => {
|
||||||
let ext = self.r.compile_macro(item, self.r.session.edition());
|
let ext = Lrc::new(self.r.compile_macro(item, self.r.session.edition()));
|
||||||
(ext, item.ident, item.span, def.legacy)
|
(ext, item.ident, item.span, def.legacy)
|
||||||
}
|
}
|
||||||
ItemKind::Fn(..) => match Self::proc_macro_stub(item) {
|
ItemKind::Fn(..) => match Self::proc_macro_stub(item) {
|
||||||
|
|
|
@ -800,7 +800,7 @@ impl<'a> Resolver<'a> {
|
||||||
|
|
||||||
/// Compile the macro into a `SyntaxExtension` and possibly replace it with a pre-defined
|
/// Compile the macro into a `SyntaxExtension` and possibly replace it with a pre-defined
|
||||||
/// extension partially or entirely for built-in macros and legacy plugin macros.
|
/// extension partially or entirely for built-in macros and legacy plugin macros.
|
||||||
crate fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> Lrc<SyntaxExtension> {
|
crate fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> SyntaxExtension {
|
||||||
let mut result = macro_rules::compile(
|
let mut result = macro_rules::compile(
|
||||||
&self.session.parse_sess, self.session.features_untracked(), item, edition
|
&self.session.parse_sess, self.session.features_untracked(), item, edition
|
||||||
);
|
);
|
||||||
|
@ -822,6 +822,6 @@ impl<'a> Resolver<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Lrc::new(result)
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use crate::ast::{self, NodeId, Attribute, Name, PatKind};
|
use crate::ast::{self, NodeId, Attribute, Name, PatKind};
|
||||||
use crate::attr::{HasAttrs, Stability, Deprecation};
|
use crate::attr::{self, HasAttrs, Stability, Deprecation};
|
||||||
use crate::source_map::SourceMap;
|
use crate::source_map::SourceMap;
|
||||||
use crate::edition::Edition;
|
use crate::edition::Edition;
|
||||||
use crate::ext::expand::{self, AstFragment, Invocation};
|
use crate::ext::expand::{self, AstFragment, Invocation};
|
||||||
use crate::ext::hygiene::{ExpnId, Transparency};
|
use crate::ext::hygiene::{ExpnId, Transparency};
|
||||||
use crate::mut_visit::{self, MutVisitor};
|
use crate::mut_visit::{self, MutVisitor};
|
||||||
use crate::parse::{self, parser, DirectoryOwnership};
|
use crate::parse::{self, parser, ParseSess, DirectoryOwnership};
|
||||||
use crate::parse::token;
|
use crate::parse::token;
|
||||||
use crate::ptr::P;
|
use crate::ptr::P;
|
||||||
use crate::symbol::{kw, sym, Ident, Symbol};
|
use crate::symbol::{kw, sym, Ident, Symbol};
|
||||||
|
@ -601,6 +601,69 @@ impl SyntaxExtension {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs a syntax extension with the given properties
|
||||||
|
/// and other properties converted from attributes.
|
||||||
|
pub fn new(
|
||||||
|
sess: &ParseSess,
|
||||||
|
kind: SyntaxExtensionKind,
|
||||||
|
span: Span,
|
||||||
|
helper_attrs: Vec<Symbol>,
|
||||||
|
edition: Edition,
|
||||||
|
name: Name,
|
||||||
|
attrs: &[ast::Attribute],
|
||||||
|
) -> SyntaxExtension {
|
||||||
|
let allow_internal_unstable =
|
||||||
|
attr::find_by_name(attrs, sym::allow_internal_unstable).map(|attr| {
|
||||||
|
attr.meta_item_list()
|
||||||
|
.map(|list| {
|
||||||
|
list.iter()
|
||||||
|
.filter_map(|it| {
|
||||||
|
let name = it.ident().map(|ident| ident.name);
|
||||||
|
if name.is_none() {
|
||||||
|
sess.span_diagnostic.span_err(
|
||||||
|
it.span(), "allow internal unstable expects feature names"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
name
|
||||||
|
})
|
||||||
|
.collect::<Vec<Symbol>>()
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
sess.span_diagnostic.span_warn(
|
||||||
|
attr.span,
|
||||||
|
"allow_internal_unstable expects list of feature names. In the future \
|
||||||
|
this will become a hard error. Please use `allow_internal_unstable(\
|
||||||
|
foo, bar)` to only allow the `foo` and `bar` features",
|
||||||
|
);
|
||||||
|
vec![sym::allow_internal_unstable_backcompat_hack].into()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut local_inner_macros = false;
|
||||||
|
if let Some(macro_export) = attr::find_by_name(attrs, sym::macro_export) {
|
||||||
|
if let Some(l) = macro_export.meta_item_list() {
|
||||||
|
local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let is_builtin = attr::contains_name(attrs, sym::rustc_builtin_macro);
|
||||||
|
|
||||||
|
SyntaxExtension {
|
||||||
|
kind,
|
||||||
|
span,
|
||||||
|
allow_internal_unstable,
|
||||||
|
allow_internal_unsafe: attr::contains_name(attrs, sym::allow_internal_unsafe),
|
||||||
|
local_inner_macros,
|
||||||
|
stability: attr::find_stability(&sess, attrs, span),
|
||||||
|
deprecation: attr::find_deprecation(&sess, attrs, span),
|
||||||
|
helper_attrs,
|
||||||
|
edition,
|
||||||
|
is_builtin,
|
||||||
|
is_derive_copy: is_builtin && name == sym::Copy,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn dummy_bang(edition: Edition) -> SyntaxExtension {
|
pub fn dummy_bang(edition: Edition) -> SyntaxExtension {
|
||||||
fn expander<'cx>(_: &'cx mut ExtCtxt<'_>, span: Span, _: &[TokenTree])
|
fn expander<'cx>(_: &'cx mut ExtCtxt<'_>, span: Span, _: &[TokenTree])
|
||||||
-> Box<dyn MacResult + 'cx> {
|
-> Box<dyn MacResult + 'cx> {
|
||||||
|
|
|
@ -360,12 +360,11 @@ pub(crate) struct Rustc<'a> {
|
||||||
|
|
||||||
impl<'a> Rustc<'a> {
|
impl<'a> Rustc<'a> {
|
||||||
pub fn new(cx: &'a ExtCtxt<'_>) -> Self {
|
pub fn new(cx: &'a ExtCtxt<'_>) -> Self {
|
||||||
// No way to determine def location for a proc macro right now, so use call location.
|
let expn_data = cx.current_expansion.id.expn_data();
|
||||||
let location = cx.current_expansion.id.expn_data().call_site;
|
|
||||||
Rustc {
|
Rustc {
|
||||||
sess: cx.parse_sess,
|
sess: cx.parse_sess,
|
||||||
def_site: cx.with_def_site_ctxt(location),
|
def_site: cx.with_def_site_ctxt(expn_data.def_site),
|
||||||
call_site: cx.with_call_site_ctxt(location),
|
call_site: cx.with_call_site_ctxt(expn_data.call_site),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use crate::ast;
|
||||||
|
use crate::attr::{self, TransparencyError};
|
||||||
use crate::edition::Edition;
|
use crate::edition::Edition;
|
||||||
use crate::ext::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander};
|
use crate::ext::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander};
|
||||||
use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind};
|
use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind};
|
||||||
|
@ -15,7 +17,6 @@ use crate::parse::token::{self, NtTT, Token};
|
||||||
use crate::parse::{Directory, ParseSess};
|
use crate::parse::{Directory, ParseSess};
|
||||||
use crate::symbol::{kw, sym, Symbol};
|
use crate::symbol::{kw, sym, Symbol};
|
||||||
use crate::tokenstream::{DelimSpan, TokenStream, TokenTree};
|
use crate::tokenstream::{DelimSpan, TokenStream, TokenTree};
|
||||||
use crate::{ast, attr, attr::TransparencyError};
|
|
||||||
|
|
||||||
use errors::{DiagnosticBuilder, FatalError};
|
use errors::{DiagnosticBuilder, FatalError};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
@ -290,6 +291,7 @@ pub fn compile(
|
||||||
def: &ast::Item,
|
def: &ast::Item,
|
||||||
edition: Edition,
|
edition: Edition,
|
||||||
) -> SyntaxExtension {
|
) -> SyntaxExtension {
|
||||||
|
let diag = &sess.span_diagnostic;
|
||||||
let lhs_nm = ast::Ident::new(sym::lhs, def.span);
|
let lhs_nm = ast::Ident::new(sym::lhs, def.span);
|
||||||
let rhs_nm = ast::Ident::new(sym::rhs, def.span);
|
let rhs_nm = ast::Ident::new(sym::rhs, def.span);
|
||||||
let tt_spec = ast::Ident::new(sym::tt, def.span);
|
let tt_spec = ast::Ident::new(sym::tt, def.span);
|
||||||
|
@ -423,13 +425,9 @@ pub fn compile(
|
||||||
let (transparency, transparency_error) = attr::find_transparency(&def.attrs, body.legacy);
|
let (transparency, transparency_error) = attr::find_transparency(&def.attrs, body.legacy);
|
||||||
match transparency_error {
|
match transparency_error {
|
||||||
Some(TransparencyError::UnknownTransparency(value, span)) =>
|
Some(TransparencyError::UnknownTransparency(value, span)) =>
|
||||||
sess.span_diagnostic.span_err(
|
diag.span_err(span, &format!("unknown macro transparency: `{}`", value)),
|
||||||
span, &format!("unknown macro transparency: `{}`", value)
|
|
||||||
),
|
|
||||||
Some(TransparencyError::MultipleTransparencyAttrs(old_span, new_span)) =>
|
Some(TransparencyError::MultipleTransparencyAttrs(old_span, new_span)) =>
|
||||||
sess.span_diagnostic.span_err(
|
diag.span_err(vec![old_span, new_span], "multiple macro transparency attributes"),
|
||||||
vec![old_span, new_span], "multiple macro transparency attributes"
|
|
||||||
),
|
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,57 +435,15 @@ pub fn compile(
|
||||||
name: def.ident, span: def.span, transparency, lhses, rhses, valid
|
name: def.ident, span: def.span, transparency, lhses, rhses, valid
|
||||||
});
|
});
|
||||||
|
|
||||||
let allow_internal_unstable =
|
SyntaxExtension::new(
|
||||||
attr::find_by_name(&def.attrs, sym::allow_internal_unstable).map(|attr| {
|
sess,
|
||||||
attr.meta_item_list()
|
SyntaxExtensionKind::LegacyBang(expander),
|
||||||
.map(|list| {
|
def.span,
|
||||||
list.iter()
|
Vec::new(),
|
||||||
.filter_map(|it| {
|
|
||||||
let name = it.ident().map(|ident| ident.name);
|
|
||||||
if name.is_none() {
|
|
||||||
sess.span_diagnostic.span_err(
|
|
||||||
it.span(),
|
|
||||||
"allow internal unstable expects feature names",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
name
|
|
||||||
})
|
|
||||||
.collect::<Vec<Symbol>>()
|
|
||||||
.into()
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
sess.span_diagnostic.span_warn(
|
|
||||||
attr.span,
|
|
||||||
"allow_internal_unstable expects list of feature names. In the \
|
|
||||||
future this will become a hard error. Please use `allow_internal_unstable(\
|
|
||||||
foo, bar)` to only allow the `foo` and `bar` features",
|
|
||||||
);
|
|
||||||
vec![sym::allow_internal_unstable_backcompat_hack].into()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut local_inner_macros = false;
|
|
||||||
if let Some(macro_export) = attr::find_by_name(&def.attrs, sym::macro_export) {
|
|
||||||
if let Some(l) = macro_export.meta_item_list() {
|
|
||||||
local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let is_builtin = attr::contains_name(&def.attrs, sym::rustc_builtin_macro);
|
|
||||||
|
|
||||||
SyntaxExtension {
|
|
||||||
kind: SyntaxExtensionKind::LegacyBang(expander),
|
|
||||||
span: def.span,
|
|
||||||
allow_internal_unstable,
|
|
||||||
allow_internal_unsafe: attr::contains_name(&def.attrs, sym::allow_internal_unsafe),
|
|
||||||
local_inner_macros,
|
|
||||||
stability: attr::find_stability(&sess, &def.attrs, def.span),
|
|
||||||
deprecation: attr::find_deprecation(&sess, &def.attrs, def.span),
|
|
||||||
helper_attrs: Vec::new(),
|
|
||||||
edition,
|
edition,
|
||||||
is_builtin,
|
def.ident.name,
|
||||||
is_derive_copy: is_builtin && def.ident.name == sym::Copy,
|
&def.attrs,
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_lhs_nt_follows(
|
fn check_lhs_nt_follows(
|
||||||
|
|
|
@ -375,10 +375,11 @@ impl<'a> Parser<'a> {
|
||||||
if let Some(directory) = directory {
|
if let Some(directory) = directory {
|
||||||
parser.directory = directory;
|
parser.directory = directory;
|
||||||
} else if !parser.token.span.is_dummy() {
|
} else if !parser.token.span.is_dummy() {
|
||||||
if let FileName::Real(mut path) =
|
if let Some(FileName::Real(path)) =
|
||||||
sess.source_map().span_to_unmapped_path(parser.token.span) {
|
&sess.source_map().lookup_char_pos(parser.token.span.lo()).file.unmapped_path {
|
||||||
path.pop();
|
if let Some(directory_path) = path.parent() {
|
||||||
parser.directory.path = Cow::from(path);
|
parser.directory.path = Cow::from(directory_path.to_path_buf());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,18 @@
|
||||||
#![feature(decl_macro)]
|
#![feature(decl_macro)]
|
||||||
#![feature(mem_take)]
|
#![feature(mem_take)]
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
|
#![feature(proc_macro_internals)]
|
||||||
|
#![feature(proc_macro_quote)]
|
||||||
#![feature(rustc_diagnostic_macros)]
|
#![feature(rustc_diagnostic_macros)]
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
|
||||||
use crate::deriving::*;
|
use crate::deriving::*;
|
||||||
|
|
||||||
use syntax::ast::Ident;
|
use syntax::ast::Ident;
|
||||||
use syntax::edition::Edition;
|
use syntax::edition::Edition;
|
||||||
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind, MacroExpanderFn};
|
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind, MacroExpanderFn};
|
||||||
|
use syntax::ext::proc_macro::BangProcMacro;
|
||||||
use syntax::symbol::sym;
|
use syntax::symbol::sym;
|
||||||
|
|
||||||
mod error_codes;
|
mod error_codes;
|
||||||
|
@ -100,4 +105,7 @@ pub fn register_builtin_macros(resolver: &mut dyn syntax::ext::base::Resolver, e
|
||||||
RustcDecodable: decodable::expand_deriving_rustc_decodable,
|
RustcDecodable: decodable::expand_deriving_rustc_decodable,
|
||||||
RustcEncodable: encodable::expand_deriving_rustc_encodable,
|
RustcEncodable: encodable::expand_deriving_rustc_encodable,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
|
||||||
|
register(sym::quote, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#![crate_type = "proc-macro"]
|
#![crate_type = "proc-macro"]
|
||||||
#![feature(proc_macro_hygiene)]
|
#![feature(proc_macro_hygiene)]
|
||||||
|
#![feature(proc_macro_quote)]
|
||||||
|
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#![crate_type = "proc-macro"]
|
#![crate_type = "proc-macro"]
|
||||||
#![feature(proc_macro_hygiene)]
|
#![feature(proc_macro_hygiene)]
|
||||||
|
#![feature(proc_macro_quote)]
|
||||||
|
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
|
||||||
use proc_macro::{quote, Span, TokenStream};
|
use proc_macro::{quote, Span, TokenStream, TokenTree};
|
||||||
|
|
||||||
fn assert_same_span(a: Span, b: Span) {
|
fn assert_same_span(a: Span, b: Span) {
|
||||||
assert_eq!(a.start(), b.start());
|
assert_eq!(a.start(), b.start());
|
||||||
|
@ -24,12 +24,22 @@ pub fn make_foo(_: TokenStream) -> TokenStream {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check that all spans are equal.
|
// Check that all spans are equal.
|
||||||
let mut span = None;
|
// FIXME: `quote!` gives def-site spans to idents and literals,
|
||||||
|
// but leaves (default) call-site spans on groups and punctuation.
|
||||||
|
let mut span_call = None;
|
||||||
|
let mut span_def = None;
|
||||||
for tt in result.clone() {
|
for tt in result.clone() {
|
||||||
match span {
|
match tt {
|
||||||
None => span = Some(tt.span()),
|
TokenTree::Ident(..) | TokenTree::Literal(..) => match span_def {
|
||||||
Some(span) => assert_same_span(tt.span(), span),
|
None => span_def = Some(tt.span()),
|
||||||
|
Some(span) => assert_same_span(tt.span(), span),
|
||||||
|
}
|
||||||
|
TokenTree::Punct(..) | TokenTree::Group(..) => match span_call {
|
||||||
|
None => span_call = Some(tt.span()),
|
||||||
|
Some(span) => assert_same_span(tt.span(), span),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
|
|
|
@ -17,11 +17,15 @@ LL | $(= $z:tt)*
|
||||||
error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fragments
|
error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fragments
|
||||||
--> $DIR/same-sequence-span.rs:20:1
|
--> $DIR/same-sequence-span.rs:20:1
|
||||||
|
|
|
|
||||||
LL | proc_macro_sequence::make_foo!();
|
LL | proc_macro_sequence::make_foo!();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^--------------------------------
|
||||||
|
| |
|
||||||
|
| _in this macro invocation
|
||||||
| |
|
| |
|
||||||
| not allowed after `expr` fragments
|
LL | |
|
||||||
| in this macro invocation
|
LL | |
|
||||||
|
LL | | fn main() {}
|
||||||
|
... |
|
||||||
|
|
|
|
||||||
= note: allowed there are: `=>`, `,` or `;`
|
= note: allowed there are: `=>`, `,` or `;`
|
||||||
|
|
||||||
|
|
12
src/test/ui/proc-macro/attributes-on-definitions.rs
Normal file
12
src/test/ui/proc-macro/attributes-on-definitions.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// check-pass
|
||||||
|
// aux-build:attributes-on-definitions.rs
|
||||||
|
|
||||||
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
|
extern crate attributes_on_definitions;
|
||||||
|
|
||||||
|
attributes_on_definitions::with_attrs!();
|
||||||
|
//~^ WARN use of deprecated item
|
||||||
|
// No errors about the use of unstable and unsafe code inside the macro.
|
||||||
|
|
||||||
|
fn main() {}
|
8
src/test/ui/proc-macro/attributes-on-definitions.stderr
Normal file
8
src/test/ui/proc-macro/attributes-on-definitions.stderr
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
warning: use of deprecated item 'attributes_on_definitions::with_attrs': test
|
||||||
|
--> $DIR/attributes-on-definitions.rs:8:1
|
||||||
|
|
|
||||||
|
LL | attributes_on_definitions::with_attrs!();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(deprecated)]` on by default
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
// force-host
|
||||||
|
// no-prefer-dynamic
|
||||||
|
|
||||||
|
#![feature(allow_internal_unsafe)]
|
||||||
|
#![feature(allow_internal_unstable)]
|
||||||
|
|
||||||
|
#![crate_type = "proc-macro"]
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
use proc_macro::*;
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
#[allow_internal_unstable(proc_macro_internals)]
|
||||||
|
#[allow_internal_unsafe]
|
||||||
|
#[deprecated(since = "1.0.0", note = "test")]
|
||||||
|
pub fn with_attrs(_: TokenStream) -> TokenStream {
|
||||||
|
"
|
||||||
|
extern crate proc_macro;
|
||||||
|
use ::proc_macro::bridge;
|
||||||
|
|
||||||
|
fn contains_unsafe() { unsafe {} }
|
||||||
|
".parse().unwrap()
|
||||||
|
}
|
|
@ -1,8 +1,19 @@
|
||||||
error: hello to you, too!
|
error: hello to you, too!
|
||||||
--> $DIR/multispan.rs:14:5
|
--> $DIR/auxiliary/multispan.rs:31:1
|
||||||
|
|
|
|
||||||
LL | hello!(hi);
|
LL | / pub fn hello(input: TokenStream) -> TokenStream {
|
||||||
| ^^^^^^^^^^^ in this macro invocation
|
LL | | if let Err(diag) = parse(input) {
|
||||||
|
LL | | diag.emit();
|
||||||
|
LL | | }
|
||||||
|
LL | |
|
||||||
|
LL | | TokenStream::new()
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
|
||||||
|
::: $DIR/multispan.rs:14:5
|
||||||
|
|
|
||||||
|
LL | hello!(hi);
|
||||||
|
| ----------- in this macro invocation
|
||||||
|
|
|
|
||||||
note: found these 'hi's
|
note: found these 'hi's
|
||||||
--> $DIR/multispan.rs:14:12
|
--> $DIR/multispan.rs:14:12
|
||||||
|
@ -11,10 +22,21 @@ LL | hello!(hi);
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: hello to you, too!
|
error: hello to you, too!
|
||||||
--> $DIR/multispan.rs:17:5
|
--> $DIR/auxiliary/multispan.rs:31:1
|
||||||
|
|
|
|
||||||
LL | hello!(hi hi);
|
LL | / pub fn hello(input: TokenStream) -> TokenStream {
|
||||||
| ^^^^^^^^^^^^^^ in this macro invocation
|
LL | | if let Err(diag) = parse(input) {
|
||||||
|
LL | | diag.emit();
|
||||||
|
LL | | }
|
||||||
|
LL | |
|
||||||
|
LL | | TokenStream::new()
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
|
||||||
|
::: $DIR/multispan.rs:17:5
|
||||||
|
|
|
||||||
|
LL | hello!(hi hi);
|
||||||
|
| -------------- in this macro invocation
|
||||||
|
|
|
|
||||||
note: found these 'hi's
|
note: found these 'hi's
|
||||||
--> $DIR/multispan.rs:17:12
|
--> $DIR/multispan.rs:17:12
|
||||||
|
@ -23,10 +45,21 @@ LL | hello!(hi hi);
|
||||||
| ^^ ^^
|
| ^^ ^^
|
||||||
|
|
||||||
error: hello to you, too!
|
error: hello to you, too!
|
||||||
--> $DIR/multispan.rs:20:5
|
--> $DIR/auxiliary/multispan.rs:31:1
|
||||||
|
|
|
|
||||||
LL | hello!(hi hi hi);
|
LL | / pub fn hello(input: TokenStream) -> TokenStream {
|
||||||
| ^^^^^^^^^^^^^^^^^ in this macro invocation
|
LL | | if let Err(diag) = parse(input) {
|
||||||
|
LL | | diag.emit();
|
||||||
|
LL | | }
|
||||||
|
LL | |
|
||||||
|
LL | | TokenStream::new()
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
|
||||||
|
::: $DIR/multispan.rs:20:5
|
||||||
|
|
|
||||||
|
LL | hello!(hi hi hi);
|
||||||
|
| ----------------- in this macro invocation
|
||||||
|
|
|
|
||||||
note: found these 'hi's
|
note: found these 'hi's
|
||||||
--> $DIR/multispan.rs:20:12
|
--> $DIR/multispan.rs:20:12
|
||||||
|
@ -35,10 +68,21 @@ LL | hello!(hi hi hi);
|
||||||
| ^^ ^^ ^^
|
| ^^ ^^ ^^
|
||||||
|
|
||||||
error: hello to you, too!
|
error: hello to you, too!
|
||||||
--> $DIR/multispan.rs:23:5
|
--> $DIR/auxiliary/multispan.rs:31:1
|
||||||
|
|
|
|
||||||
LL | hello!(hi hey hi yo hi beep beep hi hi);
|
LL | / pub fn hello(input: TokenStream) -> TokenStream {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation
|
LL | | if let Err(diag) = parse(input) {
|
||||||
|
LL | | diag.emit();
|
||||||
|
LL | | }
|
||||||
|
LL | |
|
||||||
|
LL | | TokenStream::new()
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
|
||||||
|
::: $DIR/multispan.rs:23:5
|
||||||
|
|
|
||||||
|
LL | hello!(hi hey hi yo hi beep beep hi hi);
|
||||||
|
| ---------------------------------------- in this macro invocation
|
||||||
|
|
|
|
||||||
note: found these 'hi's
|
note: found these 'hi's
|
||||||
--> $DIR/multispan.rs:23:12
|
--> $DIR/multispan.rs:23:12
|
||||||
|
@ -47,10 +91,21 @@ LL | hello!(hi hey hi yo hi beep beep hi hi);
|
||||||
| ^^ ^^ ^^ ^^ ^^
|
| ^^ ^^ ^^ ^^ ^^
|
||||||
|
|
||||||
error: hello to you, too!
|
error: hello to you, too!
|
||||||
--> $DIR/multispan.rs:24:5
|
--> $DIR/auxiliary/multispan.rs:31:1
|
||||||
|
|
|
|
||||||
LL | hello!(hi there, hi how are you? hi... hi.);
|
LL | / pub fn hello(input: TokenStream) -> TokenStream {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation
|
LL | | if let Err(diag) = parse(input) {
|
||||||
|
LL | | diag.emit();
|
||||||
|
LL | | }
|
||||||
|
LL | |
|
||||||
|
LL | | TokenStream::new()
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
|
||||||
|
::: $DIR/multispan.rs:24:5
|
||||||
|
|
|
||||||
|
LL | hello!(hi there, hi how are you? hi... hi.);
|
||||||
|
| -------------------------------------------- in this macro invocation
|
||||||
|
|
|
|
||||||
note: found these 'hi's
|
note: found these 'hi's
|
||||||
--> $DIR/multispan.rs:24:12
|
--> $DIR/multispan.rs:24:12
|
||||||
|
@ -59,10 +114,21 @@ LL | hello!(hi there, hi how are you? hi... hi.);
|
||||||
| ^^ ^^ ^^ ^^
|
| ^^ ^^ ^^ ^^
|
||||||
|
|
||||||
error: hello to you, too!
|
error: hello to you, too!
|
||||||
--> $DIR/multispan.rs:25:5
|
--> $DIR/auxiliary/multispan.rs:31:1
|
||||||
|
|
|
|
||||||
LL | hello!(whoah. hi di hi di ho);
|
LL | / pub fn hello(input: TokenStream) -> TokenStream {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation
|
LL | | if let Err(diag) = parse(input) {
|
||||||
|
LL | | diag.emit();
|
||||||
|
LL | | }
|
||||||
|
LL | |
|
||||||
|
LL | | TokenStream::new()
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
|
||||||
|
::: $DIR/multispan.rs:25:5
|
||||||
|
|
|
||||||
|
LL | hello!(whoah. hi di hi di ho);
|
||||||
|
| ------------------------------ in this macro invocation
|
||||||
|
|
|
|
||||||
note: found these 'hi's
|
note: found these 'hi's
|
||||||
--> $DIR/multispan.rs:25:19
|
--> $DIR/multispan.rs:25:19
|
||||||
|
@ -71,10 +137,21 @@ LL | hello!(whoah. hi di hi di ho);
|
||||||
| ^^ ^^
|
| ^^ ^^
|
||||||
|
|
||||||
error: hello to you, too!
|
error: hello to you, too!
|
||||||
--> $DIR/multispan.rs:26:5
|
--> $DIR/auxiliary/multispan.rs:31:1
|
||||||
|
|
|
|
||||||
LL | hello!(hi good hi and good bye);
|
LL | / pub fn hello(input: TokenStream) -> TokenStream {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation
|
LL | | if let Err(diag) = parse(input) {
|
||||||
|
LL | | diag.emit();
|
||||||
|
LL | | }
|
||||||
|
LL | |
|
||||||
|
LL | | TokenStream::new()
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
|
||||||
|
::: $DIR/multispan.rs:26:5
|
||||||
|
|
|
||||||
|
LL | hello!(hi good hi and good bye);
|
||||||
|
| -------------------------------- in this macro invocation
|
||||||
|
|
|
|
||||||
note: found these 'hi's
|
note: found these 'hi's
|
||||||
--> $DIR/multispan.rs:26:12
|
--> $DIR/multispan.rs:26:12
|
||||||
|
|
|
@ -1,8 +1,19 @@
|
||||||
error: found 2 equal signs, need exactly 3
|
error: found 2 equal signs, need exactly 3
|
||||||
--> $DIR/three-equals.rs:15:5
|
--> $DIR/auxiliary/three-equals.rs:42:1
|
||||||
|
|
|
|
||||||
LL | three_equals!(==);
|
LL | / pub fn three_equals(input: TokenStream) -> TokenStream {
|
||||||
| ^^^^^^^^^^^^^^^^^^ in this macro invocation
|
LL | | if let Err(diag) = parse(input) {
|
||||||
|
LL | | diag.emit();
|
||||||
|
LL | | return TokenStream::new();
|
||||||
|
... |
|
||||||
|
LL | | "3".parse().unwrap()
|
||||||
|
LL | | }
|
||||||
|
| |_^
|
||||||
|
|
|
||||||
|
::: $DIR/three-equals.rs:15:5
|
||||||
|
|
|
||||||
|
LL | three_equals!(==);
|
||||||
|
| ------------------ in this macro invocation
|
||||||
|
|
|
|
||||||
= help: input must be: `===`
|
= help: input must be: `===`
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue