diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 1fa9979edb8d3..d1a05964c8f64 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -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; @@ -1057,4 +1058,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); + } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2bf110d2723e7..142e987d95219 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1012,6 +1012,7 @@ pub struct ModuleData<'a> { resolutions: RefCell>>>, legacy_macro_resolutions: RefCell, Option)>>, macro_resolutions: RefCell, Span)>>, + builtin_attrs: RefCell)>>, // Macro invocations that can expand into items in this module. unresolved_invocations: RefCell>, @@ -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()), diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 920d8a6341b3d..07ea345ca066c 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -956,6 +956,26 @@ impl<'a, 'cl> Resolver<'a, 'cl> { } }; } + + for &(ident, parent_expansion, parent_legacy_scope) + in module.builtin_attrs.borrow().iter() { + let resolve_legacy = |this: &mut Self| this.resolve_legacy_scope( + ident, parent_expansion, parent_legacy_scope, true, true + ); + let resolve_modern = |this: &mut Self| this.resolve_lexical_macro_path_segment( + ident, MacroNS, parent_expansion, true, true, true, ident.span + ).map(|(binding, _)| binding).ok(); + + if let Some(binding) = resolve_legacy(self).or_else(|| resolve_modern(self)) { + 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, binding, builtin_binding); + } + } + } } fn suggest_macro_name(&mut self, name: &str, kind: MacroKind, diff --git a/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.rs b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.rs new file mode 100644 index 0000000000000..6a47e50f62dbb --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.rs @@ -0,0 +1,20 @@ +// aux-build:builtin-attrs.rs +// compile-flags:--test + +#![feature(decl_macro, test)] + +extern crate test; +extern crate builtin_attrs; +use builtin_attrs::{test, bench}; + +#[test] // OK, shadowed +fn test() {} + +#[bench] // OK, shadowed +fn bench(b: &mut test::Bencher) {} + +fn not_main() { + Test; + Bench; + NonExistent; //~ ERROR cannot find value `NonExistent` in this scope +} diff --git a/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.stderr b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.stderr new file mode 100644 index 0000000000000..db07055b6a109 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs-test.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `NonExistent` in this scope + --> $DIR/ambiguous-builtin-attrs-test.rs:19:5 + | +LL | NonExistent; //~ ERROR cannot find value `NonExistent` in this scope + | ^^^^^^^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.rs b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.rs new file mode 100644 index 0000000000000..b3a50e8fb7c33 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.rs @@ -0,0 +1,44 @@ +// aux-build:builtin-attrs.rs + +#![feature(decl_macro)] //~ ERROR `feature` is ambiguous + +extern crate builtin_attrs; +use builtin_attrs::{test, bench}; +use builtin_attrs::*; + +#[repr(C)] //~ ERROR `repr` is ambiguous +struct S; +#[cfg_attr(all(), repr(C))] //~ ERROR `repr` is ambiguous +struct SCond; + +#[cfg(all())] //~ ERROR `cfg` is ambiguous +struct A; +#[cfg(any())] // ERROR FIXME +struct A; + +#[cfg_attr(all(), cold)] // ERROR FIXME +fn g() {} +#[cfg_attr(any(), cold)] // ERROR FIXME +fn h() {} + +#[derive(Clone)] // ERROR FIXME +struct B; + +#[test] // OK, shadowed +fn test() {} + +#[bench] // OK, shadowed +fn bench() {} + +fn non_macro_expanded_location<#[repr(C)] T>() { //~ ERROR `repr` is ambiguous + match 0u8 { + #[repr(C)] //~ ERROR `repr` is ambiguous + _ => {} + } +} + +fn main() { + Test; + Bench; + NonExistent; //~ ERROR cannot find value `NonExistent` in this scope +} diff --git a/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.stderr b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.stderr new file mode 100644 index 0000000000000..2bf3082aa4228 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/ambiguous-builtin-attrs.stderr @@ -0,0 +1,118 @@ +error[E0659]: `repr` is ambiguous + --> $DIR/ambiguous-builtin-attrs.rs:9:3 + | +LL | #[repr(C)] //~ ERROR `repr` is ambiguous + | ^^^^ ambiguous name + | +note: `repr` could refer to the name imported here + --> $DIR/ambiguous-builtin-attrs.rs:7:5 + | +LL | use builtin_attrs::*; + | ^^^^^^^^^^^^^^^^ +note: `repr` could also refer to the name defined here + --> $DIR/ambiguous-builtin-attrs.rs:9:3 + | +LL | #[repr(C)] //~ ERROR `repr` is ambiguous + | ^^^^ + = note: consider adding an explicit import of `repr` to disambiguate + +error[E0659]: `repr` is ambiguous + --> $DIR/ambiguous-builtin-attrs.rs:11:19 + | +LL | #[cfg_attr(all(), repr(C))] //~ ERROR `repr` is ambiguous + | ^^^^ ambiguous name + | +note: `repr` could refer to the name imported here + --> $DIR/ambiguous-builtin-attrs.rs:7:5 + | +LL | use builtin_attrs::*; + | ^^^^^^^^^^^^^^^^ +note: `repr` could also refer to the name defined here + --> $DIR/ambiguous-builtin-attrs.rs:11:19 + | +LL | #[cfg_attr(all(), repr(C))] //~ ERROR `repr` is ambiguous + | ^^^^ + = note: consider adding an explicit import of `repr` to disambiguate + +error[E0659]: `cfg` is ambiguous + --> $DIR/ambiguous-builtin-attrs.rs:14:3 + | +LL | #[cfg(all())] //~ ERROR `cfg` is ambiguous + | ^^^ ambiguous name + | +note: `cfg` could refer to the name imported here + --> $DIR/ambiguous-builtin-attrs.rs:7:5 + | +LL | use builtin_attrs::*; + | ^^^^^^^^^^^^^^^^ +note: `cfg` could also refer to the name defined here + --> $DIR/ambiguous-builtin-attrs.rs:14:3 + | +LL | #[cfg(all())] //~ ERROR `cfg` is ambiguous + | ^^^ + = note: consider adding an explicit import of `cfg` to disambiguate + +error[E0659]: `repr` is ambiguous + --> $DIR/ambiguous-builtin-attrs.rs:33:34 + | +LL | fn non_macro_expanded_location<#[repr(C)] T>() { //~ ERROR `repr` is ambiguous + | ^^^^ ambiguous name + | +note: `repr` could refer to the name imported here + --> $DIR/ambiguous-builtin-attrs.rs:7:5 + | +LL | use builtin_attrs::*; + | ^^^^^^^^^^^^^^^^ +note: `repr` could also refer to the name defined here + --> $DIR/ambiguous-builtin-attrs.rs:33:34 + | +LL | fn non_macro_expanded_location<#[repr(C)] T>() { //~ ERROR `repr` is ambiguous + | ^^^^ + = note: consider adding an explicit import of `repr` to disambiguate + +error[E0659]: `repr` is ambiguous + --> $DIR/ambiguous-builtin-attrs.rs:35:11 + | +LL | #[repr(C)] //~ ERROR `repr` is ambiguous + | ^^^^ ambiguous name + | +note: `repr` could refer to the name imported here + --> $DIR/ambiguous-builtin-attrs.rs:7:5 + | +LL | use builtin_attrs::*; + | ^^^^^^^^^^^^^^^^ +note: `repr` could also refer to the name defined here + --> $DIR/ambiguous-builtin-attrs.rs:35:11 + | +LL | #[repr(C)] //~ ERROR `repr` is ambiguous + | ^^^^ + = note: consider adding an explicit import of `repr` to disambiguate + +error[E0659]: `feature` is ambiguous + --> $DIR/ambiguous-builtin-attrs.rs:3:4 + | +LL | #![feature(decl_macro)] //~ ERROR `feature` is ambiguous + | ^^^^^^^ ambiguous name + | +note: `feature` could refer to the name imported here + --> $DIR/ambiguous-builtin-attrs.rs:7:5 + | +LL | use builtin_attrs::*; + | ^^^^^^^^^^^^^^^^ +note: `feature` could also refer to the name defined here + --> $DIR/ambiguous-builtin-attrs.rs:3:4 + | +LL | #![feature(decl_macro)] //~ ERROR `feature` is ambiguous + | ^^^^^^^ + = note: consider adding an explicit import of `feature` to disambiguate + +error[E0425]: cannot find value `NonExistent` in this scope + --> $DIR/ambiguous-builtin-attrs.rs:43:5 + | +LL | NonExistent; //~ ERROR cannot find value `NonExistent` in this scope + | ^^^^^^^^^^^ not found in this scope + +error: aborting due to 7 previous errors + +Some errors occurred: E0425, E0659. +For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/builtin-attrs.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/builtin-attrs.rs new file mode 100644 index 0000000000000..332df815b1933 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/auxiliary/builtin-attrs.rs @@ -0,0 +1,51 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::*; + +#[proc_macro_attribute] +pub fn feature(_: TokenStream, input: TokenStream) -> TokenStream { + input +} + +#[proc_macro_attribute] +pub fn repr(_: TokenStream, input: TokenStream) -> TokenStream { + input +} + +#[proc_macro_attribute] +pub fn cfg(_: TokenStream, input: TokenStream) -> TokenStream { + input +} + +#[proc_macro_attribute] +pub fn cfg_attr(_: TokenStream, input: TokenStream) -> TokenStream { + input +} + +#[proc_macro_attribute] +pub fn derive(_: TokenStream, input: TokenStream) -> TokenStream { + input +} + +#[proc_macro_attribute] +pub fn test(_: TokenStream, input: TokenStream) -> TokenStream { + "struct Test;".parse().unwrap() +} + +#[proc_macro_attribute] +pub fn bench(_: TokenStream, input: TokenStream) -> TokenStream { + "struct Bench;".parse().unwrap() +}