Respect attributes on proc macro definitions
This commit is contained in:
@@ -530,7 +530,6 @@ impl<'a, 'tcx> CrateMetadata {
|
|||||||
id: DefIndex,
|
id: DefIndex,
|
||||||
sess: &Session)
|
sess: &Session)
|
||||||
-> FullProcMacro {
|
-> FullProcMacro {
|
||||||
|
|
||||||
let raw_macro = self.raw_proc_macro(id);
|
let raw_macro = self.raw_proc_macro(id);
|
||||||
let (name, kind, helper_attrs) = match *raw_macro {
|
let (name, kind, helper_attrs) = match *raw_macro {
|
||||||
ProcMacro::CustomDerive { trait_name, attributes, client } => {
|
ProcMacro::CustomDerive { trait_name, attributes, client } => {
|
||||||
@@ -551,16 +550,19 @@ impl<'a, 'tcx> CrateMetadata {
|
|||||||
name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new()
|
name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new()
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
let name = Symbol::intern(name);
|
||||||
let span = self.get_span(id, sess);
|
|
||||||
|
|
||||||
FullProcMacro {
|
FullProcMacro {
|
||||||
name: Symbol::intern(name),
|
name,
|
||||||
ext: Lrc::new(SyntaxExtension {
|
ext: Lrc::new(SyntaxExtension::new(
|
||||||
span,
|
&sess.parse_sess,
|
||||||
|
kind,
|
||||||
|
self.get_span(id, sess),
|
||||||
helper_attrs,
|
helper_attrs,
|
||||||
..SyntaxExtension::default(kind, root.edition)
|
root.edition,
|
||||||
})
|
name,
|
||||||
|
&self.get_attributes(&self.entry(id), sess),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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> {
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
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()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user