diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs index fc521e5edc06b..bdb50dbfb4f47 100644 --- a/src/libsyntax_expand/expand.rs +++ b/src/libsyntax_expand/expand.rs @@ -17,9 +17,10 @@ use syntax::parse::token; use syntax::parse::parser::Parser; use syntax::print::pprust; use syntax::ptr::P; +use syntax::sess::ParseSess; use syntax::symbol::{sym, Symbol}; use syntax::tokenstream::{TokenStream, TokenTree}; -use syntax::visit::Visitor; +use syntax::visit::{self, Visitor}; use syntax::util::map_in_place::MapInPlace; use errors::{Applicability, FatalError}; @@ -615,6 +616,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } InvocationKind::Attr { attr, mut item, .. } => match ext { SyntaxExtensionKind::Attr(expander) => { + self.gate_proc_macro_input(&item); self.gate_proc_macro_attr_item(span, &item); let item_tok = TokenTree::token(token::Interpolated(Lrc::new(match item { Annotatable::Item(item) => token::NtItem(item), @@ -664,6 +666,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { if !item.derive_allowed() { return fragment_kind.dummy(span); } + if let SyntaxExtensionKind::Derive(..) = ext { + self.gate_proc_macro_input(&item); + } let meta = ast::MetaItem { kind: ast::MetaItemKind::Word, span, path }; let items = expander.expand(self.cx, span, &meta, item); fragment_kind.expect_from_annotatables(items) @@ -692,21 +697,16 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) { - let (kind, gate) = match *item { - Annotatable::Item(ref item) => { - match item.kind { - ItemKind::Mod(_) if self.cx.ecfg.proc_macro_hygiene() => return, - ItemKind::Mod(_) => ("modules", sym::proc_macro_hygiene), - _ => return, - } + let kind = match item { + Annotatable::Item(item) => match &item.kind { + ItemKind::Mod(m) if m.inline => "modules", + _ => return, } - Annotatable::TraitItem(_) => return, - Annotatable::ImplItem(_) => return, - Annotatable::ForeignItem(_) => return, - Annotatable::Stmt(_) | - Annotatable::Expr(_) if self.cx.ecfg.proc_macro_hygiene() => return, - Annotatable::Stmt(_) => ("statements", sym::proc_macro_hygiene), - Annotatable::Expr(_) => ("expressions", sym::proc_macro_hygiene), + Annotatable::TraitItem(_) + | Annotatable::ImplItem(_) + | Annotatable::ForeignItem(_) => return, + Annotatable::Stmt(_) => "statements", + Annotatable::Expr(_) => "expressions", Annotatable::Arm(..) | Annotatable::Field(..) | Annotatable::FieldPat(..) @@ -716,15 +716,49 @@ impl<'a, 'b> MacroExpander<'a, 'b> { | Annotatable::Variant(..) => panic!("unexpected annotatable"), }; + if self.cx.ecfg.proc_macro_hygiene() { + return + } emit_feature_err( self.cx.parse_sess, - gate, + sym::proc_macro_hygiene, span, GateIssue::Language, &format!("custom attributes cannot be applied to {}", kind), ); } + fn gate_proc_macro_input(&self, annotatable: &Annotatable) { + struct GateProcMacroInput<'a> { + parse_sess: &'a ParseSess, + } + + impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> { + fn visit_item(&mut self, item: &'ast ast::Item) { + match &item.kind { + ast::ItemKind::Mod(module) if !module.inline => { + emit_feature_err( + self.parse_sess, + sym::proc_macro_hygiene, + item.span, + GateIssue::Language, + "non-inline modules in proc macro input are unstable", + ); + } + _ => {} + } + + visit::walk_item(self, item); + } + + fn visit_mac(&mut self, _: &'ast ast::Mac) {} + } + + if !self.cx.ecfg.proc_macro_hygiene() { + annotatable.visit_with(&mut GateProcMacroInput { parse_sess: self.cx.parse_sess }); + } + } + fn gate_proc_macro_expansion_kind(&self, span: Span, kind: AstFragmentKind) { let kind = match kind { AstFragmentKind::Expr | diff --git a/src/test/ui/proc-macro/attributes-on-modules-fail.rs b/src/test/ui/proc-macro/attributes-on-modules-fail.rs new file mode 100644 index 0000000000000..c8bc0b3437436 --- /dev/null +++ b/src/test/ui/proc-macro/attributes-on-modules-fail.rs @@ -0,0 +1,29 @@ +// aux-build:test-macros.rs + +#[macro_use] +extern crate test_macros; + +#[identity_attr] //~ ERROR custom attributes cannot be applied to modules +mod m { + pub struct X; + + type A = Y; //~ ERROR cannot find type `Y` in this scope +} + +struct Y; +type A = X; //~ ERROR cannot find type `X` in this scope + +#[derive(Copy)] //~ ERROR `derive` may only be applied to structs, enums and unions +mod n {} + +#[empty_attr] +mod module; //~ ERROR non-inline modules in proc macro input are unstable + +#[empty_attr] //~ ERROR custom attributes cannot be applied to modules +mod outer { + mod inner; //~ ERROR non-inline modules in proc macro input are unstable + + mod inner_inline {} // OK +} + +fn main() {} diff --git a/src/test/ui/proc-macro/attributes-on-modules-fail.stderr b/src/test/ui/proc-macro/attributes-on-modules-fail.stderr new file mode 100644 index 0000000000000..34a5a5aaa54fb --- /dev/null +++ b/src/test/ui/proc-macro/attributes-on-modules-fail.stderr @@ -0,0 +1,76 @@ +error[E0658]: custom attributes cannot be applied to modules + --> $DIR/attributes-on-modules-fail.rs:6:1 + | +LL | #[identity_attr] + | ^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 + = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable + +error: `derive` may only be applied to structs, enums and unions + --> $DIR/attributes-on-modules-fail.rs:16:1 + | +LL | #[derive(Copy)] + | ^^^^^^^^^^^^^^^ + +error[E0658]: non-inline modules in proc macro input are unstable + --> $DIR/attributes-on-modules-fail.rs:20:1 + | +LL | mod module; + | ^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 + = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable + +error[E0658]: non-inline modules in proc macro input are unstable + --> $DIR/attributes-on-modules-fail.rs:24:5 + | +LL | mod inner; + | ^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 + = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable + +error[E0658]: custom attributes cannot be applied to modules + --> $DIR/attributes-on-modules-fail.rs:22:1 + | +LL | #[empty_attr] + | ^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 + = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable + +error[E0412]: cannot find type `Y` in this scope + --> $DIR/attributes-on-modules-fail.rs:10:14 + | +LL | type A = Y; + | ---------^- similarly named type alias `A` defined here + | +help: a type alias with a similar name exists + | +LL | type A = A; + | ^ +help: possible candidate is found in another module, you can import it into scope + | +LL | use Y; + | + +error[E0412]: cannot find type `X` in this scope + --> $DIR/attributes-on-modules-fail.rs:14:10 + | +LL | type A = X; + | ---------^- similarly named type alias `A` defined here + | +help: a type alias with a similar name exists + | +LL | type A = A; + | ^ +help: possible candidate is found in another module, you can import it into scope + | +LL | use m::X; + | + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0412, E0658. +For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/proc-macro/attributes-on-modules.rs b/src/test/ui/proc-macro/attributes-on-modules.rs new file mode 100644 index 0000000000000..12c3ac6d9475b --- /dev/null +++ b/src/test/ui/proc-macro/attributes-on-modules.rs @@ -0,0 +1,13 @@ +// aux-build:test-macros.rs + +#[macro_use] +extern crate test_macros; + +#[identity_attr] //~ ERROR custom attributes cannot be applied to modules +mod m { + pub struct S; +} + +fn main() { + let s = m::S; +} diff --git a/src/test/ui/proc-macro/attributes-on-modules.stderr b/src/test/ui/proc-macro/attributes-on-modules.stderr new file mode 100644 index 0000000000000..df75f0bf4b149 --- /dev/null +++ b/src/test/ui/proc-macro/attributes-on-modules.stderr @@ -0,0 +1,12 @@ +error[E0658]: custom attributes cannot be applied to modules + --> $DIR/attributes-on-modules.rs:6:1 + | +LL | #[identity_attr] + | ^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 + = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/proc-macro/module.rs b/src/test/ui/proc-macro/module.rs new file mode 100644 index 0000000000000..5777ed8998397 --- /dev/null +++ b/src/test/ui/proc-macro/module.rs @@ -0,0 +1 @@ +// ignore-test diff --git a/src/test/ui/proc-macro/outer/inner.rs b/src/test/ui/proc-macro/outer/inner.rs new file mode 100644 index 0000000000000..5777ed8998397 --- /dev/null +++ b/src/test/ui/proc-macro/outer/inner.rs @@ -0,0 +1 @@ +// ignore-test