Respect attributes on proc macro definitions

This commit is contained in:
Vadim Petrochenkov 2019-08-20 21:22:32 +03:00
parent 32e5acb3eb
commit 52c62eaae4
6 changed files with 131 additions and 67 deletions

View File

@ -530,7 +530,6 @@ impl<'a, 'tcx> CrateMetadata {
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 } => {
@ -551,16 +550,19 @@ impl<'a, 'tcx> CrateMetadata {
name, SyntaxExtensionKind::Bang(Box::new(BangProcMacro { client })), Vec::new()
)
};
let span = self.get_span(id, sess);
let name = Symbol::intern(name);
FullProcMacro {
name: Symbol::intern(name),
ext: Lrc::new(SyntaxExtension {
span,
name,
ext: Lrc::new(SyntaxExtension::new(
&sess.parse_sess,
kind,
self.get_span(id, sess),
helper_attrs,
..SyntaxExtension::default(kind, root.edition)
})
root.edition,
name,
&self.get_attributes(&self.entry(id), sess),
)),
}
}

View File

@ -1,11 +1,11 @@
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::edition::Edition;
use crate::ext::expand::{self, AstFragment, Invocation};
use crate::ext::hygiene::{ExpnId, Transparency};
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::ptr::P;
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 {
fn expander<'cx>(_: &'cx mut ExtCtxt<'_>, span: Span, _: &[TokenTree])
-> Box<dyn MacResult + 'cx> {

View File

@ -1,3 +1,5 @@
use crate::ast;
use crate::attr::{self, TransparencyError};
use crate::edition::Edition;
use crate::ext::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander};
use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind};
@ -15,7 +17,6 @@ use crate::parse::token::{self, NtTT, Token};
use crate::parse::{Directory, ParseSess};
use crate::symbol::{kw, sym, Symbol};
use crate::tokenstream::{DelimSpan, TokenStream, TokenTree};
use crate::{ast, attr, attr::TransparencyError};
use errors::{DiagnosticBuilder, FatalError};
use log::debug;
@ -290,6 +291,7 @@ pub fn compile(
def: &ast::Item,
edition: Edition,
) -> SyntaxExtension {
let diag = &sess.span_diagnostic;
let lhs_nm = ast::Ident::new(sym::lhs, def.span);
let rhs_nm = ast::Ident::new(sym::rhs, 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);
match transparency_error {
Some(TransparencyError::UnknownTransparency(value, span)) =>
sess.span_diagnostic.span_err(
span, &format!("unknown macro transparency: `{}`", value)
),
diag.span_err(span, &format!("unknown macro transparency: `{}`", value)),
Some(TransparencyError::MultipleTransparencyAttrs(old_span, new_span)) =>
sess.span_diagnostic.span_err(
vec![old_span, new_span], "multiple macro transparency attributes"
),
diag.span_err(vec![old_span, new_span], "multiple macro transparency attributes"),
None => {}
}
@ -437,57 +435,15 @@ pub fn compile(
name: def.ident, span: def.span, transparency, lhses, rhses, valid
});
let allow_internal_unstable =
attr::find_by_name(&def.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(&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(),
SyntaxExtension::new(
sess,
SyntaxExtensionKind::LegacyBang(expander),
def.span,
Vec::new(),
edition,
is_builtin,
is_derive_copy: is_builtin && def.ident.name == sym::Copy,
}
def.ident.name,
&def.attrs,
)
}
fn check_lhs_nt_follows(

View 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() {}

View 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

View File

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