resolve: Introduce two sub-namespaces in macro namespace

This commit is contained in:
Vadim Petrochenkov
2018-09-08 22:19:53 +03:00
parent 994cdd9185
commit beb3b5d22c
10 changed files with 64 additions and 35 deletions
+18 -11
View File
@@ -118,11 +118,21 @@ pub struct ProcMacError {
warn_msg: &'static str,
}
// For compatibility bang macros are skipped when resolving potentially built-in attributes.
fn macro_kind_mismatch(name: Name, requirement: Option<MacroKind>, candidate: Option<MacroKind>)
-> bool {
requirement == Some(MacroKind::Attr) && candidate == Some(MacroKind::Bang) &&
(name == "test" || name == "bench" || is_builtin_attr_name(name))
// Macro namespace is separated into two sub-namespaces, one for bang macros and
// one for attribute-like macros (attributes, derives).
// We ignore resolutions from one sub-namespace when searching names in scope for another.
fn sub_namespace_mismatch(requirement: Option<MacroKind>, candidate: Option<MacroKind>) -> bool {
#[derive(PartialEq)]
enum SubNS { Bang, AttrLike }
let sub_ns = |kind| match kind {
MacroKind::Bang => Some(SubNS::Bang),
MacroKind::Attr | MacroKind::Derive => Some(SubNS::AttrLike),
MacroKind::ProcMacroStub => None,
};
let requirement = requirement.and_then(|kind| sub_ns(kind));
let candidate = candidate.and_then(|kind| sub_ns(kind));
// "No specific sub-namespace" means "matches anything" for both requirements and candidates.
candidate.is_some() && requirement.is_some() && candidate != requirement
}
impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
@@ -641,10 +651,7 @@ enum WhereToResolve<'a> {
}
}
WhereToResolve::BuiltinAttrs => {
// FIXME: Only built-in attributes are not considered as candidates for
// non-attributes to fight off regressions on stable channel (#53205).
// We need to come up with some more principled approach instead.
if kind == Some(MacroKind::Attr) && is_builtin_attr_name(ident.name) {
if is_builtin_attr_name(ident.name) {
let binding = (Def::NonMacroAttr(NonMacroAttrKind::Builtin),
ty::Visibility::Public, ident.span, Mark::root())
.to_name_binding(self.arenas);
@@ -765,7 +772,7 @@ macro_rules! continue_search { () => {
match result {
Ok(result) => {
if macro_kind_mismatch(ident.name, kind, result.0.macro_kind()) {
if sub_namespace_mismatch(kind, result.0.macro_kind()) {
continue_search!();
}
@@ -829,7 +836,7 @@ fn resolve_legacy_scope(
parent_scope: &ParentScope<'a>,
record_used: bool,
) -> Option<&'a NameBinding<'a>> {
if macro_kind_mismatch(ident.name, kind, Some(MacroKind::Bang)) {
if sub_namespace_mismatch(kind, Some(MacroKind::Bang)) {
return None;
}
@@ -0,0 +1,2 @@
#[macro_export]
macro_rules! my_attr { () => () }
@@ -0,0 +1,11 @@
// no-prefer-dynamic
#![crate_type = "proc-macro"]
extern crate proc_macro;
use proc_macro::*;
#[proc_macro_derive(MyTrait, attributes(my_attr))]
pub fn foo(_: TokenStream) -> TokenStream {
TokenStream::new()
}
@@ -0,0 +1,16 @@
// compile-pass
// aux-build:derive-helper-shadowed.rs
// aux-build:derive-helper-shadowed-2.rs
#[macro_use]
extern crate derive_helper_shadowed;
#[macro_use(my_attr)]
extern crate derive_helper_shadowed_2;
macro_rules! my_attr { () => () }
#[derive(MyTrait)]
#[my_attr] // OK
struct S;
fn main() {}
+1 -1
View File
@@ -9,5 +9,5 @@
// except according to those terms.
fn main() {
concat!(test!()); //~ ERROR `test` can only be used in attributes
concat!(test!()); //~ ERROR cannot find macro `test!` in this scope
}
+2 -2
View File
@@ -1,7 +1,7 @@
error: `test` can only be used in attributes
error: cannot find macro `test!` in this scope
--> $DIR/issue-11692-2.rs:12:13
|
LL | concat!(test!()); //~ ERROR `test` can only be used in attributes
LL | concat!(test!()); //~ ERROR cannot find macro `test!` in this scope
| ^^^^
error: aborting due to previous error
@@ -1,16 +1,3 @@
// 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.
#[derive(inline)] //~ ERROR cannot find derive macro `inline` in this scope
struct S;
fn main() {
inline!(); //~ ERROR cannot find macro `inline!` in this scope
}
@@ -1,14 +1,8 @@
error: cannot find derive macro `inline` in this scope
--> $DIR/macro-path-prelude-fail-3.rs:11:10
|
LL | #[derive(inline)] //~ ERROR cannot find derive macro `inline` in this scope
| ^^^^^^
error: cannot find macro `inline!` in this scope
--> $DIR/macro-path-prelude-fail-3.rs:15:5
--> $DIR/macro-path-prelude-fail-3.rs:2:5
|
LL | inline!(); //~ ERROR cannot find macro `inline!` in this scope
| ^^^^^^ help: you could try the macro: `line`
error: aborting due to 2 previous errors
error: aborting due to previous error
@@ -0,0 +1,4 @@
#[derive(inline)] //~ ERROR expected a macro, found built-in attribute
struct S;
fn main() {}
@@ -0,0 +1,8 @@
error: expected a macro, found built-in attribute
--> $DIR/macro-path-prelude-fail-4.rs:1:10
|
LL | #[derive(inline)] //~ ERROR expected a macro, found built-in attribute
| ^^^^^^
error: aborting due to previous error