Auto merge of #52383 - petrochenkov:pmns, r=alexcrichton
resolve: Functions introducing procedural macros reserve a slot in the macro namespace as well Similarly to https://github.com/rust-lang/rust/pull/52234, this gives us symmetry between internal and external views of a crate, but in this case it's always an error to call a procedural macro in the same crate in which it's defined. Closes https://github.com/rust-lang/rust/issues/52225
This commit is contained in:
commit
82e5c9c8e2
@ -98,7 +98,8 @@ impl_stable_hash_for!(enum ::syntax::ast::AsmDialect {
|
|||||||
impl_stable_hash_for!(enum ::syntax::ext::base::MacroKind {
|
impl_stable_hash_for!(enum ::syntax::ext::base::MacroKind {
|
||||||
Bang,
|
Bang,
|
||||||
Attr,
|
Attr,
|
||||||
Derive
|
Derive,
|
||||||
|
ProcMacroStub,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ use syntax::attr;
|
|||||||
|
|
||||||
use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId};
|
use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId};
|
||||||
use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind, Variant};
|
use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind, Variant};
|
||||||
use syntax::ext::base::SyntaxExtension;
|
use syntax::ext::base::{MacroKind, SyntaxExtension};
|
||||||
use syntax::ext::base::Determinacy::Undetermined;
|
use syntax::ext::base::Determinacy::Undetermined;
|
||||||
use syntax::ext::hygiene::Mark;
|
use syntax::ext::hygiene::Mark;
|
||||||
use syntax::ext::tt::macro_rules;
|
use syntax::ext::tt::macro_rules;
|
||||||
@ -335,6 +335,24 @@ impl<'a> Resolver<'a> {
|
|||||||
ItemKind::Fn(..) => {
|
ItemKind::Fn(..) => {
|
||||||
let def = Def::Fn(self.definitions.local_def_id(item.id));
|
let def = Def::Fn(self.definitions.local_def_id(item.id));
|
||||||
self.define(parent, ident, ValueNS, (def, vis, sp, expansion));
|
self.define(parent, ident, ValueNS, (def, vis, sp, expansion));
|
||||||
|
|
||||||
|
// Functions introducing procedural macros reserve a slot
|
||||||
|
// in the macro namespace as well (see #52225).
|
||||||
|
if attr::contains_name(&item.attrs, "proc_macro") ||
|
||||||
|
attr::contains_name(&item.attrs, "proc_macro_attribute") {
|
||||||
|
let def = Def::Macro(def.def_id(), MacroKind::ProcMacroStub);
|
||||||
|
self.define(parent, ident, MacroNS, (def, vis, sp, expansion));
|
||||||
|
}
|
||||||
|
if let Some(attr) = attr::find_by_name(&item.attrs, "proc_macro_derive") {
|
||||||
|
if let Some(trait_attr) =
|
||||||
|
attr.meta_item_list().and_then(|list| list.get(0).cloned()) {
|
||||||
|
if let Some(ident) = trait_attr.name().map(Ident::with_empty_ctxt) {
|
||||||
|
let sp = trait_attr.span;
|
||||||
|
let def = Def::Macro(def.def_id(), MacroKind::ProcMacroStub);
|
||||||
|
self.define(parent, ident, MacroNS, (def, vis, sp, expansion));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// These items live in the type namespace.
|
// These items live in the type namespace.
|
||||||
|
@ -321,6 +321,10 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||||||
InvocationKind::Attr { attr: None, .. } => return Ok(None),
|
InvocationKind::Attr { attr: None, .. } => return Ok(None),
|
||||||
_ => self.resolve_invoc_to_def(invoc, scope, force)?,
|
_ => self.resolve_invoc_to_def(invoc, scope, force)?,
|
||||||
};
|
};
|
||||||
|
if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
|
||||||
|
self.report_proc_macro_stub(invoc.span());
|
||||||
|
return Err(Determinacy::Determined);
|
||||||
|
}
|
||||||
let def_id = def.def_id();
|
let def_id = def.def_id();
|
||||||
|
|
||||||
self.macro_defs.insert(invoc.expansion_data.mark, def_id);
|
self.macro_defs.insert(invoc.expansion_data.mark, def_id);
|
||||||
@ -338,9 +342,13 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||||||
|
|
||||||
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
|
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
|
||||||
-> Result<Lrc<SyntaxExtension>, Determinacy> {
|
-> Result<Lrc<SyntaxExtension>, Determinacy> {
|
||||||
self.resolve_macro_to_def(scope, path, kind, force).map(|def| {
|
self.resolve_macro_to_def(scope, path, kind, force).and_then(|def| {
|
||||||
|
if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
|
||||||
|
self.report_proc_macro_stub(path.span);
|
||||||
|
return Err(Determinacy::Determined);
|
||||||
|
}
|
||||||
self.unused_macros.remove(&def.def_id());
|
self.unused_macros.remove(&def.def_id());
|
||||||
self.get_macro(def)
|
Ok(self.get_macro(def))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,6 +371,11 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Resolver<'a> {
|
impl<'a> Resolver<'a> {
|
||||||
|
fn report_proc_macro_stub(&self, span: Span) {
|
||||||
|
self.session.span_err(span,
|
||||||
|
"can't use a procedural macro from the same crate that defines it");
|
||||||
|
}
|
||||||
|
|
||||||
fn resolve_invoc_to_def(&mut self, invoc: &mut Invocation, scope: Mark, force: bool)
|
fn resolve_invoc_to_def(&mut self, invoc: &mut Invocation, scope: Mark, force: bool)
|
||||||
-> Result<Def, Determinacy> {
|
-> Result<Def, Determinacy> {
|
||||||
let (attr, traits, item) = match invoc.kind {
|
let (attr, traits, item) = match invoc.kind {
|
||||||
|
@ -571,6 +571,8 @@ pub enum MacroKind {
|
|||||||
Attr,
|
Attr,
|
||||||
/// A derive attribute macro - #[derive(Foo)]
|
/// A derive attribute macro - #[derive(Foo)]
|
||||||
Derive,
|
Derive,
|
||||||
|
/// A view of a procedural macro from the same crate that defines it.
|
||||||
|
ProcMacroStub,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MacroKind {
|
impl MacroKind {
|
||||||
@ -579,6 +581,7 @@ impl MacroKind {
|
|||||||
MacroKind::Bang => "macro",
|
MacroKind::Bang => "macro",
|
||||||
MacroKind::Attr => "attribute macro",
|
MacroKind::Attr => "attribute macro",
|
||||||
MacroKind::Derive => "derive macro",
|
MacroKind::Derive => "derive macro",
|
||||||
|
MacroKind::ProcMacroStub => "crate-local procedural macro",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,7 +232,7 @@ pub enum InvocationKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Invocation {
|
impl Invocation {
|
||||||
fn span(&self) -> Span {
|
pub fn span(&self) -> Span {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
InvocationKind::Bang { span, .. } => span,
|
InvocationKind::Bang { span, .. } => span,
|
||||||
InvocationKind::Attr { attr: Some(ref attr), .. } => attr.span,
|
InvocationKind::Attr { attr: Some(ref attr), .. } => attr.span,
|
||||||
|
@ -146,11 +146,6 @@ impl<'a> CollectProcMacros<'a> {
|
|||||||
"cannot override a built-in #[derive] mode");
|
"cannot override a built-in #[derive] mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.derives.iter().any(|d| d.trait_name == trait_name) {
|
|
||||||
self.handler.span_err(trait_attr.span(),
|
|
||||||
"derive mode defined twice in this crate");
|
|
||||||
}
|
|
||||||
|
|
||||||
let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr {
|
let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr {
|
||||||
if !attr.check_name("attributes") {
|
if !attr.check_name("attributes") {
|
||||||
self.handler.span_err(attr.span(), "second argument must be `attributes`")
|
self.handler.span_err(attr.span(), "second argument must be `attributes`")
|
||||||
|
@ -21,7 +21,7 @@ pub fn foo(input: TokenStream) -> TokenStream {
|
|||||||
input
|
input
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(A)] //~ ERROR: derive mode defined twice in this crate
|
#[proc_macro_derive(A)] //~ ERROR the name `A` is defined multiple times
|
||||||
pub fn bar(input: TokenStream) -> TokenStream {
|
pub fn bar(input: TokenStream) -> TokenStream {
|
||||||
input
|
input
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// no-prefer-dynamic
|
||||||
|
|
||||||
|
#![feature(proc_macro)]
|
||||||
|
#![crate_type = "proc-macro"]
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
use proc_macro::*;
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn my_macro(input: TokenStream) -> TokenStream {
|
||||||
|
input
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn my_macro_attr(input: TokenStream, _: TokenStream) -> TokenStream {
|
||||||
|
input
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(MyTrait)]
|
||||||
|
pub fn my_macro_derive(input: TokenStream) -> TokenStream {
|
||||||
|
input
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_bang1() {
|
||||||
|
my_macro!(); //~ ERROR can't use a procedural macro from the same crate that defines it
|
||||||
|
}
|
||||||
|
fn check_bang2() {
|
||||||
|
my_macro_attr!(); //~ ERROR can't use a procedural macro from the same crate that defines it
|
||||||
|
}
|
||||||
|
fn check_bang3() {
|
||||||
|
MyTrait!(); //~ ERROR can't use a procedural macro from the same crate that defines it
|
||||||
|
}
|
||||||
|
|
||||||
|
#[my_macro] //~ ERROR can't use a procedural macro from the same crate that defines it
|
||||||
|
fn check_attr1() {}
|
||||||
|
#[my_macro_attr] //~ ERROR can't use a procedural macro from the same crate that defines it
|
||||||
|
fn check_attr2() {}
|
||||||
|
#[MyTrait] //~ ERROR can't use a procedural macro from the same crate that defines it
|
||||||
|
fn check_attr3() {}
|
||||||
|
|
||||||
|
#[derive(my_macro)] //~ ERROR can't use a procedural macro from the same crate that defines it
|
||||||
|
struct CheckDerive1;
|
||||||
|
#[derive(my_macro_attr)] //~ ERROR can't use a procedural macro from the same crate that defines it
|
||||||
|
struct CheckDerive2;
|
||||||
|
#[derive(MyTrait)] //~ ERROR can't use a procedural macro from the same crate that defines it
|
||||||
|
struct CheckDerive3;
|
@ -0,0 +1,56 @@
|
|||||||
|
error: can't use a procedural macro from the same crate that defines it
|
||||||
|
--> $DIR/macro-namespace-reserved-2.rs:35:5
|
||||||
|
|
|
||||||
|
LL | my_macro!(); //~ ERROR can't use a procedural macro from the same crate that defines it
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: can't use a procedural macro from the same crate that defines it
|
||||||
|
--> $DIR/macro-namespace-reserved-2.rs:38:5
|
||||||
|
|
|
||||||
|
LL | my_macro_attr!(); //~ ERROR can't use a procedural macro from the same crate that defines it
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: can't use a procedural macro from the same crate that defines it
|
||||||
|
--> $DIR/macro-namespace-reserved-2.rs:41:5
|
||||||
|
|
|
||||||
|
LL | MyTrait!(); //~ ERROR can't use a procedural macro from the same crate that defines it
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: can't use a procedural macro from the same crate that defines it
|
||||||
|
--> $DIR/macro-namespace-reserved-2.rs:44:1
|
||||||
|
|
|
||||||
|
LL | #[my_macro] //~ ERROR can't use a procedural macro from the same crate that defines it
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: can't use a procedural macro from the same crate that defines it
|
||||||
|
--> $DIR/macro-namespace-reserved-2.rs:46:1
|
||||||
|
|
|
||||||
|
LL | #[my_macro_attr] //~ ERROR can't use a procedural macro from the same crate that defines it
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: can't use a procedural macro from the same crate that defines it
|
||||||
|
--> $DIR/macro-namespace-reserved-2.rs:48:1
|
||||||
|
|
|
||||||
|
LL | #[MyTrait] //~ ERROR can't use a procedural macro from the same crate that defines it
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: can't use a procedural macro from the same crate that defines it
|
||||||
|
--> $DIR/macro-namespace-reserved-2.rs:51:10
|
||||||
|
|
|
||||||
|
LL | #[derive(my_macro)] //~ ERROR can't use a procedural macro from the same crate that defines it
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
||||||
|
error: can't use a procedural macro from the same crate that defines it
|
||||||
|
--> $DIR/macro-namespace-reserved-2.rs:53:10
|
||||||
|
|
|
||||||
|
LL | #[derive(my_macro_attr)] //~ ERROR can't use a procedural macro from the same crate that defines it
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: can't use a procedural macro from the same crate that defines it
|
||||||
|
--> $DIR/macro-namespace-reserved-2.rs:55:10
|
||||||
|
|
|
||||||
|
LL | #[derive(MyTrait)] //~ ERROR can't use a procedural macro from the same crate that defines it
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 9 previous errors
|
||||||
|
|
47
src/test/ui-fulldeps/proc-macro/macro-namespace-reserved.rs
Normal file
47
src/test/ui-fulldeps/proc-macro/macro-namespace-reserved.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// no-prefer-dynamic
|
||||||
|
|
||||||
|
#![feature(proc_macro, decl_macro)]
|
||||||
|
#![crate_type = "proc-macro"]
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
use proc_macro::*;
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn my_macro(input: TokenStream) -> TokenStream {
|
||||||
|
input
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn my_macro_attr(input: TokenStream, _: TokenStream) -> TokenStream {
|
||||||
|
input
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_derive(MyTrait)]
|
||||||
|
pub fn my_macro_derive(input: TokenStream) -> TokenStream {
|
||||||
|
input
|
||||||
|
}
|
||||||
|
|
||||||
|
macro my_macro() {} //~ ERROR the name `my_macro` is defined multiple times
|
||||||
|
macro my_macro_attr() {} //~ ERROR the name `my_macro_attr` is defined multiple times
|
||||||
|
macro MyTrait() {} //~ ERROR the name `MyTrait` is defined multiple times
|
||||||
|
|
||||||
|
#[proc_macro_derive(SameName)]
|
||||||
|
pub fn foo(input: TokenStream) -> TokenStream {
|
||||||
|
input
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn SameName(input: TokenStream) -> TokenStream {
|
||||||
|
//~^ ERROR the name `SameName` is defined multiple times
|
||||||
|
input
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
error[E0428]: the name `my_macro` is defined multiple times
|
||||||
|
--> $DIR/macro-namespace-reserved.rs:34:1
|
||||||
|
|
|
||||||
|
LL | pub fn my_macro(input: TokenStream) -> TokenStream {
|
||||||
|
| -------------------------------------------------- previous definition of the macro `my_macro` here
|
||||||
|
...
|
||||||
|
LL | macro my_macro() {} //~ ERROR the name `my_macro` is defined multiple times
|
||||||
|
| ^^^^^^^^^^^^^^^^ `my_macro` redefined here
|
||||||
|
|
|
||||||
|
= note: `my_macro` must be defined only once in the macro namespace of this module
|
||||||
|
|
||||||
|
error[E0428]: the name `my_macro_attr` is defined multiple times
|
||||||
|
--> $DIR/macro-namespace-reserved.rs:35:1
|
||||||
|
|
|
||||||
|
LL | pub fn my_macro_attr(input: TokenStream, _: TokenStream) -> TokenStream {
|
||||||
|
| ----------------------------------------------------------------------- previous definition of the macro `my_macro_attr` here
|
||||||
|
...
|
||||||
|
LL | macro my_macro_attr() {} //~ ERROR the name `my_macro_attr` is defined multiple times
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ `my_macro_attr` redefined here
|
||||||
|
|
|
||||||
|
= note: `my_macro_attr` must be defined only once in the macro namespace of this module
|
||||||
|
|
||||||
|
error[E0428]: the name `MyTrait` is defined multiple times
|
||||||
|
--> $DIR/macro-namespace-reserved.rs:36:1
|
||||||
|
|
|
||||||
|
LL | #[proc_macro_derive(MyTrait)]
|
||||||
|
| ------- previous definition of the macro `MyTrait` here
|
||||||
|
...
|
||||||
|
LL | macro MyTrait() {} //~ ERROR the name `MyTrait` is defined multiple times
|
||||||
|
| ^^^^^^^^^^^^^^^ `MyTrait` redefined here
|
||||||
|
|
|
||||||
|
= note: `MyTrait` must be defined only once in the macro namespace of this module
|
||||||
|
|
||||||
|
error[E0428]: the name `SameName` is defined multiple times
|
||||||
|
--> $DIR/macro-namespace-reserved.rs:44:1
|
||||||
|
|
|
||||||
|
LL | #[proc_macro_derive(SameName)]
|
||||||
|
| -------- previous definition of the macro `SameName` here
|
||||||
|
...
|
||||||
|
LL | pub fn SameName(input: TokenStream) -> TokenStream {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SameName` redefined here
|
||||||
|
|
|
||||||
|
= note: `SameName` must be defined only once in the macro namespace of this module
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0428`.
|
Loading…
x
Reference in New Issue
Block a user