Skip to content

Commit

Permalink
resolve: Future proof resolutions for potentially built-in attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
petrochenkov committed Sep 3, 2018
1 parent 634d886 commit 3ef8754
Show file tree
Hide file tree
Showing 7 changed files with 239 additions and 1 deletion.
10 changes: 10 additions & 0 deletions src/librustc_resolve/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use syntax::ext::base::{MacroKind, SyntaxExtension};
use syntax::ext::base::Determinacy::Undetermined;
use syntax::ext::hygiene::Mark;
use syntax::ext::tt::macro_rules;
use syntax::feature_gate::is_builtin_attr;
use syntax::parse::token::{self, Token};
use syntax::std_inject::injected_crate_name;
use syntax::symbol::keywords;
Expand Down Expand Up @@ -1060,4 +1061,13 @@ impl<'a, 'b, 'cl> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b, 'cl> {
}
}
}

fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
if !attr.is_sugared_doc && is_builtin_attr(attr) {
self.resolver.current_module.builtin_attrs.borrow_mut().push((
attr.path.segments[0].ident, self.expansion, self.current_legacy_scope
));
}
visit::walk_attribute(self, attr);
}
}
2 changes: 2 additions & 0 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,7 @@ pub struct ModuleData<'a> {
resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, Mark, LegacyScope<'a>, Option<Def>)>>,
macro_resolutions: RefCell<Vec<(Box<[Ident]>, Span)>>,
builtin_attrs: RefCell<Vec<(Ident, Mark, LegacyScope<'a>)>>,

// Macro invocations that can expand into items in this module.
unresolved_invocations: RefCell<FxHashSet<Mark>>,
Expand Down Expand Up @@ -1050,6 +1051,7 @@ impl<'a> ModuleData<'a> {
resolutions: RefCell::new(FxHashMap()),
legacy_macro_resolutions: RefCell::new(Vec::new()),
macro_resolutions: RefCell::new(Vec::new()),
builtin_attrs: RefCell::new(Vec::new()),
unresolved_invocations: RefCell::new(FxHashSet()),
no_implicit_prelude: false,
glob_importers: RefCell::new(Vec::new()),
Expand Down
40 changes: 39 additions & 1 deletion src/librustc_resolve/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,19 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
}
WhereToResolve::MacroPrelude => {
match self.macro_prelude.get(&ident.name).cloned() {
Some(binding) => Ok((binding, FromPrelude(true))),
Some(binding) => {
let mut result = Ok((binding, FromPrelude(true)));
// HACK: Keep some built-in attributes working even if they are
// shadowed by other built-in or standard library macros.
// We need to come up with some more principled approach instead.
if is_attr && (ident.name == "cfg" || ident.name == "thread_local") {
if let Def::Macro(_, MacroKind::Bang) =
binding.def_ignoring_ambiguity() {
result = Err(Determinacy::Determined);
}
}
result
}
None => Err(Determinacy::Determined),
}
}
Expand Down Expand Up @@ -928,6 +940,32 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
}
};
}

for &(ident, parent_expansion, parent_legacy_scope)
in module.builtin_attrs.borrow().iter() {
let resolution = if ident.name == "doc" {
// HACK: Some sugared doc comments in macros lose their memory about being
// sugared doc comments and become shadowed by other macros.
// We need to come up with some more principled approach instead.
None
} else {
self.resolve_legacy_scope(ident, parent_expansion, parent_legacy_scope, true)
}.or_else(|| {
self.resolve_lexical_macro_path_segment(ident, MacroNS, parent_expansion, true,
true, true, ident.span)
.map(|(binding, _)| binding).ok()
});

if let Some(binding) = resolution {
if binding.def_ignoring_ambiguity() !=
Def::NonMacroAttr(NonMacroAttrKind::Builtin) {
let builtin_binding = (Def::NonMacroAttr(NonMacroAttrKind::Builtin),
ty::Visibility::Public, ident.span, Mark::root())
.to_name_binding(self.arenas);
self.report_ambiguity_error(ident.name, ident.span, binding, builtin_binding);
}
}
}
}

fn suggest_macro_name(&mut self, name: &str, kind: MacroKind,
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/macros/ambiguous-builtin-attrs-test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// compile-flags:--test

#![feature(decl_macro, test)]

extern crate test;

macro test() {}

#[test] //~ ERROR `test` is ambiguous
fn test() {}

macro bench() {}

#[bench] //~ ERROR `bench` is ambiguous
fn bench(b: &mut test::Bencher) {}

fn main() {}
37 changes: 37 additions & 0 deletions src/test/ui/macros/ambiguous-builtin-attrs-test.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
error[E0659]: `test` is ambiguous
--> $DIR/ambiguous-builtin-attrs-test.rs:9:3
|
LL | #[test] //~ ERROR `test` is ambiguous
| ^^^^
|
note: `test` could refer to the name defined here
--> $DIR/ambiguous-builtin-attrs-test.rs:7:1
|
LL | macro test() {}
| ^^^^^^^^^^^^^^^
note: `test` could also refer to the name defined here
--> $DIR/ambiguous-builtin-attrs-test.rs:9:3
|
LL | #[test] //~ ERROR `test` is ambiguous
| ^^^^

error[E0659]: `bench` is ambiguous
--> $DIR/ambiguous-builtin-attrs-test.rs:14:3
|
LL | #[bench] //~ ERROR `bench` is ambiguous
| ^^^^^
|
note: `bench` could refer to the name defined here
--> $DIR/ambiguous-builtin-attrs-test.rs:12:1
|
LL | macro bench() {}
| ^^^^^^^^^^^^^^^^
note: `bench` could also refer to the name defined here
--> $DIR/ambiguous-builtin-attrs-test.rs:14:3
|
LL | #[bench] //~ ERROR `bench` is ambiguous
| ^^^^^

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0659`.
46 changes: 46 additions & 0 deletions src/test/ui/macros/ambiguous-builtin-attrs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#![feature(decl_macro)]

macro repr() {}

#[repr(C)] //~ ERROR `repr` is ambiguous
struct S;
#[cfg_attr(all(), repr(C))] //~ ERROR `repr` is ambiguous
struct SCond;

macro cfg() {}

#[cfg(all())] //~ ERROR `cfg` is ambiguous
struct A;
#[cfg(any())] // ERROR FIXME
struct A;

macro cfg_attr() {}

#[cfg_attr(all(), cold)] // ERROR FIXME
fn g() {}
#[cfg_attr(any(), cold)] // ERROR FIXME
fn h() {}

macro derive() {}

#[derive(Clone)] // ERROR FIXME
struct B;

macro test() {}

#[test] // ERROR FIXME
fn test() {}

macro bench() {}

#[bench] // ERROR FIXME
fn bench() {}

macro_rules! inline { () => () }

#[inline] //~ ERROR `inline` is ambiguous
fn f() {}
#[cfg_attr(all(), inline)] //~ ERROR `inline` is ambiguous
fn f_cond() {}

fn main() {}
88 changes: 88 additions & 0 deletions src/test/ui/macros/ambiguous-builtin-attrs.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
error[E0659]: `repr` is ambiguous
--> $DIR/ambiguous-builtin-attrs.rs:5:3
|
LL | #[repr(C)] //~ ERROR `repr` is ambiguous
| ^^^^
|
note: `repr` could refer to the name defined here
--> $DIR/ambiguous-builtin-attrs.rs:3:1
|
LL | macro repr() {}
| ^^^^^^^^^^^^^^^
note: `repr` could also refer to the name defined here
--> $DIR/ambiguous-builtin-attrs.rs:5:3
|
LL | #[repr(C)] //~ ERROR `repr` is ambiguous
| ^^^^

error[E0659]: `repr` is ambiguous
--> $DIR/ambiguous-builtin-attrs.rs:7:19
|
LL | #[cfg_attr(all(), repr(C))] //~ ERROR `repr` is ambiguous
| ^^^^
|
note: `repr` could refer to the name defined here
--> $DIR/ambiguous-builtin-attrs.rs:3:1
|
LL | macro repr() {}
| ^^^^^^^^^^^^^^^
note: `repr` could also refer to the name defined here
--> $DIR/ambiguous-builtin-attrs.rs:7:19
|
LL | #[cfg_attr(all(), repr(C))] //~ ERROR `repr` is ambiguous
| ^^^^

error[E0659]: `cfg` is ambiguous
--> $DIR/ambiguous-builtin-attrs.rs:12:3
|
LL | #[cfg(all())] //~ ERROR `cfg` is ambiguous
| ^^^
|
note: `cfg` could refer to the name defined here
--> $DIR/ambiguous-builtin-attrs.rs:10:1
|
LL | macro cfg() {}
| ^^^^^^^^^^^^^^
note: `cfg` could also refer to the name defined here
--> $DIR/ambiguous-builtin-attrs.rs:12:3
|
LL | #[cfg(all())] //~ ERROR `cfg` is ambiguous
| ^^^

error[E0659]: `inline` is ambiguous
--> $DIR/ambiguous-builtin-attrs.rs:41:3
|
LL | #[inline] //~ ERROR `inline` is ambiguous
| ^^^^^^
|
note: `inline` could refer to the name defined here
--> $DIR/ambiguous-builtin-attrs.rs:39:1
|
LL | macro_rules! inline { () => () }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: `inline` could also refer to the name defined here
--> $DIR/ambiguous-builtin-attrs.rs:41:3
|
LL | #[inline] //~ ERROR `inline` is ambiguous
| ^^^^^^

error[E0659]: `inline` is ambiguous
--> $DIR/ambiguous-builtin-attrs.rs:43:19
|
LL | #[cfg_attr(all(), inline)] //~ ERROR `inline` is ambiguous
| ^^^^^^
|
note: `inline` could refer to the name defined here
--> $DIR/ambiguous-builtin-attrs.rs:39:1
|
LL | macro_rules! inline { () => () }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: `inline` could also refer to the name defined here
--> $DIR/ambiguous-builtin-attrs.rs:43:19
|
LL | #[cfg_attr(all(), inline)] //~ ERROR `inline` is ambiguous
| ^^^^^^

error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0659`.

0 comments on commit 3ef8754

Please sign in to comment.