diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 7334131a1c01d..c1f2cb7224a71 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(warnings)] //! This crate is responsible for the part of name resolution that doesn't require type checker. //! //! Module structure of the crate is built here. @@ -180,6 +181,30 @@ impl<'ra> ParentScope<'ra> { derives: &[], } } + + /// Creates a scope that is empty. + fn empty(arenas: &'ra ResolverArenas<'ra>) -> ParentScope<'ra> { + let root_module = arenas.new_module( + None, + ModuleKind::Def(DefKind::Mod, rustc_hir::def_id::CRATE_DEF_ID.to_def_id(), None), + rustc_middle::ty::Visibility::Public, + rustc_span::ExpnId::root(), + DUMMY_SP, + false, + ); + + ParentScope::module( + arenas.new_module( + Some(root_module), + ModuleKind::Block, + rustc_middle::ty::Visibility::Public, + rustc_span::ExpnId::root(), + DUMMY_SP, + false, + ), + arenas, + ) + } } #[derive(Copy, Debug, Clone)] @@ -478,6 +503,8 @@ enum PathResult<'ra> { /// In this case, `module` will point to `a`. module: Option>, /// The segment name of target + /// + /// In this case, that will be `not_exist`. segment_name: Symbol, error_implied_by_parse_error: bool, message: String, @@ -1313,10 +1340,30 @@ pub struct Resolver<'ra, 'tcx> { unused_macro_rules: FxIndexMap>, proc_macro_stubs: FxHashSet = default::fx_hash_set(), /// Traces collected during macro resolution and validated when it's complete. + /// + /// Tuple members: + /// + /// 1. If this is an inner attribute macro, like `#![rustfmt]`, this is the + /// node ID of the item that the attribute is applied to + /// 2. Identifier of the macro + /// 3. The kind of macro it is + /// 4. The parent scope in which this macro was resolved in + /// 5. + /// 6. single_segment_macro_resolutions: - CmRefCell, Option>, Option)>>, + CmRefCell, Ident, MacroKind, ParentScope<'ra>, Option>, Option)>>, + /// Tuple members: + /// + /// 1. If this is an inner attribute macro, like `#![rustfmt]`, this is the + /// node ID of the item that the attribute is applied to + /// 2. Path to the macro + /// 3. Span of the full path + /// 4. The kind of macro it is + /// 5. The parent scope in which this macro was resolved in + /// 6. + /// 7. multi_segment_macro_resolutions: - CmRefCell, Span, MacroKind, ParentScope<'ra>, Option, Namespace)>>, + CmRefCell, Vec, Span, MacroKind, ParentScope<'ra>, Option, Namespace)>>, builtin_attrs: Vec<(Ident, ParentScope<'ra>)> = Vec::new(), /// `derive(Copy)` marks items they are applied to so they are treated specially later. /// Derive macros cannot modify the item themselves and have to store the markers in the global @@ -2610,8 +2657,7 @@ fn module_to_string(mut module: Module<'_>) -> Option { loop { if let ModuleKind::Def(.., name) = module.kind { if let Some(parent) = module.parent { - // `unwrap` is safe: the presence of a parent means it's not the crate root. - names.push(name.unwrap()); + names.push(name.expect("the presence of a parent means it's not the crate root")); module = parent } else { break; diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index f0e757b2d673d..cb417cfc50798 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -275,11 +275,15 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } }; - let (mut derives, mut inner_attr, mut deleg_impl) = (&[][..], false, None); + // inner_attr: Only `Some` if this macro is an inner attribute. + // + // Stores the span + expansion ID of the target item that this inner attribute applies to. + let (mut derives, mut inner_attr, mut deleg_impl) = (&[][..], None, None); + let (path, kind) = match invoc.kind { - InvocationKind::Attr { ref attr, derives: ref attr_derives, .. } => { + InvocationKind::Attr { ref attr, derives: ref attr_derives, ref item, .. } => { derives = self.arenas.alloc_ast_paths(attr_derives); - inner_attr = attr.style == ast::AttrStyle::Inner; + inner_attr = (attr.style == ast::AttrStyle::Inner).then(|| (invoc_id, item.span())); (&attr.get_normal_item().path, MacroKind::Attr) } InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang), @@ -577,7 +581,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { path: &ast::Path, kind: MacroKind, supports_macro_expansion: SupportsMacroExpansion, - inner_attr: bool, + inner_attr: Option<(LocalExpnId, Span)>, parent_scope: &ParentScope<'ra>, node_id: NodeId, force: bool, @@ -588,6 +592,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let (ext, res) = match self.cm().resolve_macro_or_delegation_path( path, kind, + inner_attr, parent_scope, force, deleg_impl, @@ -661,7 +666,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match supports_macro_expansion { SupportsMacroExpansion::No => Some(("a", "non-macro attribute")), SupportsMacroExpansion::Yes { supports_inner_attrs } => { - if inner_attr && !supports_inner_attrs { + if inner_attr.is_some() && !supports_inner_attrs { Some(("a", "non-macro inner attribute")) } else { None @@ -700,7 +705,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // We are trying to avoid reporting this error if other related errors were reported. - if res != Res::Err && inner_attr && !self.tcx.features().custom_inner_attributes() { + if res != Res::Err && inner_attr.is_some() && !self.tcx.features().custom_inner_attributes() + { let is_macro = match res { Res::Def(..) => true, Res::NonMacroAttr(..) => false, @@ -779,6 +785,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.resolve_macro_or_delegation_path( path, MacroKind::Derive, + None, parent_scope, force, None, @@ -790,8 +797,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn resolve_macro_or_delegation_path<'r>( mut self: CmResolver<'r, 'ra, 'tcx>, - ast_path: &ast::Path, - kind: MacroKind, + ast_path: &ast::Path, // Path to the macro (e.g. `foo::bar!()`) + kind: MacroKind, // What kind of macro it is (e.g. `Bang`) + inner_attr: Option<(LocalExpnId, Span)>, // if this is an inner attribute, span of the item it applies to parent_scope: &ParentScope<'ra>, force: bool, deleg_impl: Option<(LocalDefId, Span)>, @@ -802,7 +810,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let path_span = ast_path.span; let mut path = Segment::from_path(ast_path); - // Possibly apply the macro helper hack + // Possibly apply the macro helper hack, if #[macro_export(local_inner_macros)] is applied + // + // ident!(...) -> $crate::ident!(...) if deleg_impl.is_none() && kind == MacroKind::Bang && let [segment] = path.as_slice() @@ -812,6 +822,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { path.insert(0, Segment::from_ident(root)); } + let parent_scope = + if inner_attr.is_some() { &ParentScope::empty(self.arenas) } else { parent_scope }; + let res = if deleg_impl.is_some() || path.len() > 1 { let ns = if deleg_impl.is_some() { TypeNS } else { MacroNS }; let res = match self.reborrow().maybe_resolve_path( @@ -832,6 +845,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; self.multi_segment_macro_resolutions.borrow_mut(&self).push(( + inner_attr, path, path_span, kind, @@ -859,6 +873,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } self.single_segment_macro_resolutions.borrow_mut(&self).push(( + inner_attr, path[0].ident, kind, *parent_scope, @@ -896,6 +911,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Ok((ext, res)) } + /// See also `resolve_macro_or_delegation_path` pub(crate) fn finalize_macro_resolutions(&mut self, krate: &Crate) { let check_consistency = |this: &Self, path: &[Segment], @@ -930,8 +946,36 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } }; + let get_inner_module = |this: &Self, node_id, span: Span| { + let parent_did = this.invocation_parent(node_id); + let parent_module = this.get_module(parent_did.into())?; + + let mut child_module = None; + + parent_module.for_each_child(&this, |_, _, child_span, _, data| { + if span.contains(child_span) + && let Some(did) = data.res().opt_def_id() + && let Some(module) = this.get_module(did) + { + child_module = Some(module); + } + }); + + // `child_module` will be `None` if the inner attribute applies to the crate root, + // in which case it makes sense to resolve in `parent_module` (the crate root) + Some(child_module.unwrap_or(parent_module)) + }; + let macro_resolutions = self.multi_segment_macro_resolutions.take(self); - for (mut path, path_span, kind, parent_scope, initial_res, ns) in macro_resolutions { + for (inner_attr, mut path, path_span, kind, mut parent_scope, initial_res, ns) in + macro_resolutions + { + if let Some((node_id, span)) = inner_attr + && let Some(module) = get_inner_module(&self, node_id, span) + { + parent_scope.module = module; + } + // FIXME: Path resolution will ICE if segment IDs present. for seg in &mut path { seg.id = None; @@ -1034,7 +1078,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let macro_resolutions = self.single_segment_macro_resolutions.take(self); - for (ident, kind, parent_scope, initial_binding, sugg_span) in macro_resolutions { + for (inner_attr, ident, kind, mut parent_scope, initial_binding, sugg_span) in + macro_resolutions + { + if let Some((node_id, span)) = inner_attr + && let Some(module) = get_inner_module(&self, node_id, span) + { + parent_scope.module = module; + } + match self.cm().resolve_ident_in_scope_set( ident, ScopeSet::Macro(kind), diff --git a/tests/ui/macros/auxiliary/rustfmt.rs b/tests/ui/macros/auxiliary/rustfmt.rs new file mode 100644 index 0000000000000..e20f11eb6e7d7 --- /dev/null +++ b/tests/ui/macros/auxiliary/rustfmt.rs @@ -0,0 +1,7 @@ +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn skip(_: TokenStream, input: TokenStream) -> TokenStream { + "compile_error! { \"x\" }".parse().unwrap() +} diff --git a/tests/ui/macros/inner.rs b/tests/ui/macros/inner.rs new file mode 100644 index 0000000000000..e50f28d26d35c --- /dev/null +++ b/tests/ui/macros/inner.rs @@ -0,0 +1,21 @@ +// proc-macro: rustfmt.rs +#![feature(custom_inner_attributes)] +#![feature(macro_attr)] + +mod a { + #![clippy::ignore] + //~^ ERROR cannot find `ignore` in `clippy` + //~| ERROR `clippy` is ambiguous + + pub mod clippy {} +} + +mod b { + #![clippy::ignore] + //~^ ERROR cannot find `ignore` in `clippy` + //~| ERROR `clippy` is ambiguous + + use a::clippy; +} + +fn main() {} diff --git a/tests/ui/macros/inner.stderr b/tests/ui/macros/inner.stderr new file mode 100644 index 0000000000000..695ab823a93d6 --- /dev/null +++ b/tests/ui/macros/inner.stderr @@ -0,0 +1,46 @@ +error[E0433]: cannot find `ignore` in `clippy` + --> $DIR/inner.rs:6:16 + | +LL | #![clippy::ignore] + | ^^^^^^ could not find `ignore` in `clippy` + +error[E0433]: cannot find `ignore` in `clippy` + --> $DIR/inner.rs:14:16 + | +LL | #![clippy::ignore] + | ^^^^^^ could not find `ignore` in `clippy` + +error[E0659]: `clippy` is ambiguous + --> $DIR/inner.rs:6:8 + | +LL | #![clippy::ignore] + | ^^^^^^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution + = note: `clippy` could refer to a tool module +note: `clippy` could also refer to the module defined here + --> $DIR/inner.rs:10:5 + | +LL | pub mod clippy {} + | ^^^^^^^^^^^^^^^^^ + = help: use `self::clippy` to refer to this module unambiguously + +error[E0659]: `clippy` is ambiguous + --> $DIR/inner.rs:14:8 + | +LL | #![clippy::ignore] + | ^^^^^^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution + = note: `clippy` could refer to a tool module +note: `clippy` could also refer to the module imported here + --> $DIR/inner.rs:18:9 + | +LL | use a::clippy; + | ^^^^^^^^^ + = help: use `self::clippy` to refer to this module unambiguously + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0433, E0659. +For more information about an error, try `rustc --explain E0433`. diff --git a/tests/ui/proc-macro/weird-braces.rs b/tests/ui/proc-macro/weird-braces.rs index 1197156f6b03d..632d01d69db8d 100644 --- a/tests/ui/proc-macro/weird-braces.rs +++ b/tests/ui/proc-macro/weird-braces.rs @@ -16,8 +16,8 @@ trait Bar {} #[print_target_and_args(first_outer)] #[print_target_and_args(second_outer)] impl Bar<{1 > 0}> for Foo<{true}> { - #![print_target_and_args(first_inner)] - #![print_target_and_args(second_inner)] + #![crate::print_target_and_args(first_inner)] + #![crate::print_target_and_args(second_inner)] } fn main() {} diff --git a/tests/ui/proc-macro/weird-braces.stdout b/tests/ui/proc-macro/weird-braces.stdout index 0215deb05c302..ab31663a8bc94 100644 --- a/tests/ui/proc-macro/weird-braces.stdout +++ b/tests/ui/proc-macro/weird-braces.stdout @@ -7,20 +7,20 @@ PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ ] PRINT-ATTR INPUT (DISPLAY): #[print_target_and_args(second_outer)] impl Bar<{1 > 0}> for Foo<{true}> { - #![print_target_and_args(first_inner)] - #![print_target_and_args(second_inner)] + #![crate::print_target_and_args(first_inner)] + #![crate::print_target_and_args(second_inner)] } PRINT-ATTR RE-COLLECTED (DISPLAY): #[print_target_and_args(second_outer)] impl Bar < { 1 > 0 } > for Foo < { true } > { - #![print_target_and_args(first_inner)] - #![print_target_and_args(second_inner)] + #![crate::print_target_and_args(first_inner)] + #![crate::print_target_and_args(second_inner)] } PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): #[print_target_and_args(second_outer)] impl Bar < { 1 > 0 } > for Foo < { true } > { - #! [print_target_and_args(first_inner)] #! - [print_target_and_args(second_inner)] + #! [crate :: print_target_and_args(first_inner)] #! + [crate :: print_target_and_args(second_inner)] } PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { @@ -133,22 +133,36 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Group { delimiter: Bracket, stream: TokenStream [ + Ident { + ident: "crate", + span: $DIR/weird-braces.rs:19:8: 19:13 (#0), + }, + Punct { + ch: ':', + spacing: Joint, + span: $DIR/weird-braces.rs:19:13: 19:14 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/weird-braces.rs:19:14: 19:15 (#0), + }, Ident { ident: "print_target_and_args", - span: $DIR/weird-braces.rs:19:8: 19:29 (#0), + span: $DIR/weird-braces.rs:19:15: 19:36 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "first_inner", - span: $DIR/weird-braces.rs:19:30: 19:41 (#0), + span: $DIR/weird-braces.rs:19:37: 19:48 (#0), }, ], - span: $DIR/weird-braces.rs:19:29: 19:42 (#0), + span: $DIR/weird-braces.rs:19:36: 19:49 (#0), }, ], - span: $DIR/weird-braces.rs:19:7: 19:43 (#0), + span: $DIR/weird-braces.rs:19:7: 19:50 (#0), }, Punct { ch: '#', @@ -163,22 +177,36 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Group { delimiter: Bracket, stream: TokenStream [ + Ident { + ident: "crate", + span: $DIR/weird-braces.rs:20:8: 20:13 (#0), + }, + Punct { + ch: ':', + spacing: Joint, + span: $DIR/weird-braces.rs:20:13: 20:14 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/weird-braces.rs:20:14: 20:15 (#0), + }, Ident { ident: "print_target_and_args", - span: $DIR/weird-braces.rs:20:8: 20:29 (#0), + span: $DIR/weird-braces.rs:20:15: 20:36 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "second_inner", - span: $DIR/weird-braces.rs:20:30: 20:42 (#0), + span: $DIR/weird-braces.rs:20:37: 20:49 (#0), }, ], - span: $DIR/weird-braces.rs:20:29: 20:43 (#0), + span: $DIR/weird-braces.rs:20:36: 20:50 (#0), }, ], - span: $DIR/weird-braces.rs:20:7: 20:44 (#0), + span: $DIR/weird-braces.rs:20:7: 20:51 (#0), }, ], span: $DIR/weird-braces.rs:18:35: 21:2 (#0), @@ -193,18 +221,18 @@ PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ ] PRINT-ATTR INPUT (DISPLAY): impl Bar<{1 > 0}> for Foo<{true}> { - #![print_target_and_args(first_inner)] - #![print_target_and_args(second_inner)] + #![crate::print_target_and_args(first_inner)] + #![crate::print_target_and_args(second_inner)] } PRINT-ATTR RE-COLLECTED (DISPLAY): impl Bar < { 1 > 0 } > for Foo < { true } > { - #![print_target_and_args(first_inner)] - #![print_target_and_args(second_inner)] + #![crate::print_target_and_args(first_inner)] + #![crate::print_target_and_args(second_inner)] } PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): impl Bar < { 1 > 0 } > for Foo < { true } > { - #! [print_target_and_args(first_inner)] #! - [print_target_and_args(second_inner)] + #! [crate :: print_target_and_args(first_inner)] #! + [crate :: print_target_and_args(second_inner)] } PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { @@ -292,22 +320,36 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Group { delimiter: Bracket, stream: TokenStream [ + Ident { + ident: "crate", + span: $DIR/weird-braces.rs:19:8: 19:13 (#0), + }, + Punct { + ch: ':', + spacing: Joint, + span: $DIR/weird-braces.rs:19:13: 19:14 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/weird-braces.rs:19:14: 19:15 (#0), + }, Ident { ident: "print_target_and_args", - span: $DIR/weird-braces.rs:19:8: 19:29 (#0), + span: $DIR/weird-braces.rs:19:15: 19:36 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "first_inner", - span: $DIR/weird-braces.rs:19:30: 19:41 (#0), + span: $DIR/weird-braces.rs:19:37: 19:48 (#0), }, ], - span: $DIR/weird-braces.rs:19:29: 19:42 (#0), + span: $DIR/weird-braces.rs:19:36: 19:49 (#0), }, ], - span: $DIR/weird-braces.rs:19:7: 19:43 (#0), + span: $DIR/weird-braces.rs:19:7: 19:50 (#0), }, Punct { ch: '#', @@ -322,22 +364,36 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Group { delimiter: Bracket, stream: TokenStream [ + Ident { + ident: "crate", + span: $DIR/weird-braces.rs:20:8: 20:13 (#0), + }, + Punct { + ch: ':', + spacing: Joint, + span: $DIR/weird-braces.rs:20:13: 20:14 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/weird-braces.rs:20:14: 20:15 (#0), + }, Ident { ident: "print_target_and_args", - span: $DIR/weird-braces.rs:20:8: 20:29 (#0), + span: $DIR/weird-braces.rs:20:15: 20:36 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "second_inner", - span: $DIR/weird-braces.rs:20:30: 20:42 (#0), + span: $DIR/weird-braces.rs:20:37: 20:49 (#0), }, ], - span: $DIR/weird-braces.rs:20:29: 20:43 (#0), + span: $DIR/weird-braces.rs:20:36: 20:50 (#0), }, ], - span: $DIR/weird-braces.rs:20:7: 20:44 (#0), + span: $DIR/weird-braces.rs:20:7: 20:51 (#0), }, ], span: $DIR/weird-braces.rs:18:35: 21:2 (#0), @@ -347,14 +403,15 @@ PRINT-ATTR_ARGS INPUT (DISPLAY): first_inner PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "first_inner", - span: $DIR/weird-braces.rs:19:30: 19:41 (#0), + span: $DIR/weird-braces.rs:19:37: 19:48 (#0), }, ] -PRINT-ATTR INPUT (DISPLAY): impl Bar<{1 > 0}> for Foo<{true}> { #![print_target_and_args(second_inner)] } +PRINT-ATTR INPUT (DISPLAY): impl Bar<{1 > 0}> for Foo<{true}> +{ #![crate::print_target_and_args(second_inner)] } PRINT-ATTR RE-COLLECTED (DISPLAY): impl Bar < { 1 > 0 } > for Foo < { true } > -{ #![print_target_and_args(second_inner)] } +{ #![crate::print_target_and_args(second_inner)] } PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): impl Bar < { 1 > 0 } > for Foo < { true } > -{ #! [print_target_and_args(second_inner)] } +{ #! [crate :: print_target_and_args(second_inner)] } PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "impl", @@ -441,22 +498,36 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Group { delimiter: Bracket, stream: TokenStream [ + Ident { + ident: "crate", + span: $DIR/weird-braces.rs:20:8: 20:13 (#0), + }, + Punct { + ch: ':', + spacing: Joint, + span: $DIR/weird-braces.rs:20:13: 20:14 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/weird-braces.rs:20:14: 20:15 (#0), + }, Ident { ident: "print_target_and_args", - span: $DIR/weird-braces.rs:20:8: 20:29 (#0), + span: $DIR/weird-braces.rs:20:15: 20:36 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "second_inner", - span: $DIR/weird-braces.rs:20:30: 20:42 (#0), + span: $DIR/weird-braces.rs:20:37: 20:49 (#0), }, ], - span: $DIR/weird-braces.rs:20:29: 20:43 (#0), + span: $DIR/weird-braces.rs:20:36: 20:50 (#0), }, ], - span: $DIR/weird-braces.rs:20:7: 20:44 (#0), + span: $DIR/weird-braces.rs:20:7: 20:51 (#0), }, ], span: $DIR/weird-braces.rs:18:35: 21:2 (#0), @@ -466,7 +537,7 @@ PRINT-ATTR_ARGS INPUT (DISPLAY): second_inner PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [ Ident { ident: "second_inner", - span: $DIR/weird-braces.rs:20:30: 20:42 (#0), + span: $DIR/weird-braces.rs:20:37: 20:49 (#0), }, ] PRINT-ATTR INPUT (DISPLAY): impl Bar<{1 > 0}> for Foo<{true}> {} diff --git a/tests/ui/resolve/auxiliary/has_helper_attr.rs b/tests/ui/resolve/auxiliary/has_helper_attr.rs new file mode 100644 index 0000000000000..18ad8f15c2cff --- /dev/null +++ b/tests/ui/resolve/auxiliary/has_helper_attr.rs @@ -0,0 +1,10 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_derive(has_helper_attr, attributes(helper))] +pub fn has_helper_attr( + item: TokenStream, +) -> TokenStream { + TokenStream::new() +} diff --git a/tests/ui/resolve/inner-attr-inert.rs b/tests/ui/resolve/inner-attr-inert.rs new file mode 100644 index 0000000000000..5f7d84d23e3a7 --- /dev/null +++ b/tests/ui/resolve/inner-attr-inert.rs @@ -0,0 +1,138 @@ +//@ proc-macro: has_helper_attr.rs +#![feature(custom_inner_attributes)] +#![feature(macro_attr)] +#![feature(stmt_expr_attributes)] +#![feature(const_block_items)] +#![feature(register_tool)] +#![register_tool(custom)] +#![feature(decl_macro)] + +mod rustfmt_inner { + #![rustfmt::skip] +} + +mod rustfmt_ambig_unresolved { + #![rustfmt::skip] + //~^ ERROR cannot find `skip` in `rustfmt` + //~| ERROR `rustfmt` is ambiguous + + mod rustfmt {} +} + +// like above, but import exists +mod rustfmt_ambig { + #![rustfmt::skip] + //~^ ERROR `rustfmt` is ambiguous + + mod rustfmt { + pub macro skip() {} + } +} + +mod rustfmt_inner_renamed { + #![rust_fmt::skip] + + use rustfmt as rust_fmt; + //~^ ERROR unresolved import `rustfmt` +} + +#[custom::attr] +mod both_forms { + #![custom::attr] + + #[custom::attr] + mod both_forms_inner { + #![custom::attr] + } +} + +extern crate has_helper_attr; + +#[derive(has_helper_attr::has_helper_attr)] +struct InnerHelperUsed { + #[helper] + field: [(); { + #[helper] + mod inner { + #![helper] + //~^ ERROR cannot find attribute `helper` in this scope + + mod inner { + #![helper] + //~^ ERROR cannot find attribute `helper` in this scope + } + } + + #[helper_renamed] + mod inner_2 {} + + use helper as helper_renamed; + //~^ ERROR unresolved import `helper` + + 0 + }], +} + +mod rustfmt_ambig_via_macro { + #![rustfmt::skip] + //~^ ERROR cannot find `skip` in `rustfmt` + //~| ERROR `rustfmt` is ambiguous + + macro_rules! define { + () => { mod rustfmt {} }; + } + + define!(); +} + +// In these test cases, when we refer to a name that does not exist, +// we throw an error, even though if the name does exist, that attribute is +// NOT used. (inner attribute resolution happens from inside the module) + +mod clippy { + #[macro_export] + macro_rules! example { + attr() () => { compile_error!() }; + } + pub use crate::example; +} + +mod zx { + #![clippy::example] + #![clippy::non_existing] +} + +trait Z { + #![clippy::example] + #![clippy::non_existing] + //~^ ERROR cannot find `non_existing` in `clippy` +} + +struct Zm; + +impl Z for Zm { + #![clippy::example] + #![clippy::non_existing] + //~^ ERROR cannot find `non_existing` in `clippy` +} + +const { + #![clippy::example] + //~^ ERROR an inner attribute is not permitted in this context +} + +const _: () = { + #![clippy::example] + #![clippy::non_existing] +}; + +mod zy { + #![clippy] + //~^ ERROR cannot find attribute `clippy` in this scope +} + +fn main() { + #![clippy::example] + #![clippy::non_existing] + //~^ ERROR cannot find `non_existing` in `clippy` +} diff --git a/tests/ui/resolve/inner-attr-inert.stderr b/tests/ui/resolve/inner-attr-inert.stderr new file mode 100644 index 0000000000000..7240f4b874293 --- /dev/null +++ b/tests/ui/resolve/inner-attr-inert.stderr @@ -0,0 +1,153 @@ +error: an inner attribute is not permitted in this context + --> $DIR/inner-attr-inert.rs:120:5 + | +LL | #![clippy::example] + | ^^^^^^^^^^^^^^^^^^^ +... +LL | / const _: () = { +LL | | #![clippy::example] +LL | | #![clippy::non_existing] +LL | | }; + | |__- the inner attribute doesn't annotate this constant item + | + = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files + +error[E0432]: unresolved import `helper` + --> $DIR/inner-attr-inert.rs:69:13 + | +LL | use helper as helper_renamed; + | ^^^^^^^^^^^^^^^^^^^^^^^^ no `helper` in the root + +error[E0432]: unresolved import `rustfmt` + --> $DIR/inner-attr-inert.rs:35:9 + | +LL | use rustfmt as rust_fmt; + | ^^^^^^^^^^^^^^^^^^^ no `rustfmt` in the root + | +note: these modules exist but are inaccessible + --> $DIR/inner-attr-inert.rs:19:5 + | +LL | mod rustfmt {} + | ^^^^^^^^^^^ `rustfmt_ambig_unresolved::rustfmt`: not accessible +... +LL | mod rustfmt { + | ^^^^^^^^^^^ `rustfmt_ambig::rustfmt`: not accessible +... +LL | () => { mod rustfmt {} }; + | ^^^^^^^^^^^ `rustfmt_ambig_via_macro::rustfmt`: not accessible +... +LL | define!(); + | --------- in this macro invocation + = note: this error originates in the macro `define` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0433]: cannot find `skip` in `rustfmt` + --> $DIR/inner-attr-inert.rs:15:17 + | +LL | #![rustfmt::skip] + | ^^^^ could not find `skip` in `rustfmt` + +error[E0433]: cannot find `skip` in `rustfmt` + --> $DIR/inner-attr-inert.rs:77:17 + | +LL | #![rustfmt::skip] + | ^^^^ could not find `skip` in `rustfmt` + +error[E0433]: cannot find `non_existing` in `clippy` + --> $DIR/inner-attr-inert.rs:107:16 + | +LL | #![clippy::non_existing] + | ^^^^^^^^^^^^ could not find `non_existing` in `clippy` + +error[E0433]: cannot find `non_existing` in `clippy` + --> $DIR/inner-attr-inert.rs:115:16 + | +LL | #![clippy::non_existing] + | ^^^^^^^^^^^^ could not find `non_existing` in `clippy` + +error[E0433]: cannot find `non_existing` in `clippy` + --> $DIR/inner-attr-inert.rs:136:16 + | +LL | #![clippy::non_existing] + | ^^^^^^^^^^^^ could not find `non_existing` in `clippy` + +error: cannot find attribute `helper` in this scope + --> $DIR/inner-attr-inert.rs:57:16 + | +LL | #![helper] + | ^^^^^^ + | + = note: `helper` is an attribute that can be used by the derive macro `has_helper_attr`, you might be missing a `derive` attribute + +error: cannot find attribute `helper` in this scope + --> $DIR/inner-attr-inert.rs:61:20 + | +LL | #![helper] + | ^^^^^^ + | +help: `helper` is an attribute that can be used by the derive macro `has_helper_attr`, you might be missing a `derive` attribute + | +LL + #[derive(has_helper_attr)] +LL | mod inner { + | + +error: cannot find attribute `clippy` in this scope + --> $DIR/inner-attr-inert.rs:130:8 + | +LL | #![clippy] + | ^^^^^^ + +error[E0659]: `rustfmt` is ambiguous + --> $DIR/inner-attr-inert.rs:15:8 + | +LL | #![rustfmt::skip] + | ^^^^^^^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution + = note: `rustfmt` could refer to a tool module +note: `rustfmt` could also refer to the module defined here + --> $DIR/inner-attr-inert.rs:19:5 + | +LL | mod rustfmt {} + | ^^^^^^^^^^^^^^ + = help: use `self::rustfmt` to refer to this module unambiguously + +error[E0659]: `rustfmt` is ambiguous + --> $DIR/inner-attr-inert.rs:24:8 + | +LL | #![rustfmt::skip] + | ^^^^^^^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution + = note: `rustfmt` could refer to a tool module +note: `rustfmt` could also refer to the module defined here + --> $DIR/inner-attr-inert.rs:27:5 + | +LL | / mod rustfmt { +LL | | pub macro skip() {} +LL | | } + | |_____^ + = help: use `self::rustfmt` to refer to this module unambiguously + +error[E0659]: `rustfmt` is ambiguous + --> $DIR/inner-attr-inert.rs:77:8 + | +LL | #![rustfmt::skip] + | ^^^^^^^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution + = note: `rustfmt` could refer to a tool module +note: `rustfmt` could also refer to the module defined here + --> $DIR/inner-attr-inert.rs:82:17 + | +LL | () => { mod rustfmt {} }; + | ^^^^^^^^^^^^^^ +... +LL | define!(); + | --------- in this macro invocation + = help: use `self::rustfmt` to refer to this module unambiguously + = note: this error originates in the macro `define` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 14 previous errors + +Some errors have detailed explanations: E0432, E0433, E0659. +For more information about an error, try `rustc --explain E0432`.