Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 50 additions & 4 deletions compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -478,6 +503,8 @@ enum PathResult<'ra> {
/// In this case, `module` will point to `a`.
module: Option<ModuleOrUniformRoot<'ra>>,
/// The segment name of target
///
/// In this case, that will be `not_exist`.
segment_name: Symbol,
error_implied_by_parse_error: bool,
message: String,
Expand Down Expand Up @@ -1313,10 +1340,30 @@ pub struct Resolver<'ra, 'tcx> {
unused_macro_rules: FxIndexMap<NodeId, DenseBitSet<usize>>,
proc_macro_stubs: FxHashSet<LocalDefId> = 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<Vec<(Ident, MacroKind, ParentScope<'ra>, Option<Decl<'ra>>, Option<Span>)>>,
CmRefCell<Vec<(Option<(LocalExpnId, Span)>, Ident, MacroKind, ParentScope<'ra>, Option<Decl<'ra>>, Option<Span>)>>,
/// 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<Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'ra>, Option<Res>, Namespace)>>,
CmRefCell<Vec<(Option<(LocalExpnId, Span)>, Vec<Segment>, Span, MacroKind, ParentScope<'ra>, Option<Res>, 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
Expand Down Expand Up @@ -2610,8 +2657,7 @@ fn module_to_string(mut module: Module<'_>) -> Option<String> {
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;
Expand Down
74 changes: 63 additions & 11 deletions compiler/rustc_resolve/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -779,6 +785,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
self.resolve_macro_or_delegation_path(
path,
MacroKind::Derive,
None,
parent_scope,
force,
None,
Expand All @@ -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)>,
Expand All @@ -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()
Expand All @@ -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(
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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],
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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),
Expand Down
7 changes: 7 additions & 0 deletions tests/ui/macros/auxiliary/rustfmt.rs
Original file line number Diff line number Diff line change
@@ -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()
}
21 changes: 21 additions & 0 deletions tests/ui/macros/inner.rs
Original file line number Diff line number Diff line change
@@ -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() {}
46 changes: 46 additions & 0 deletions tests/ui/macros/inner.stderr
Original file line number Diff line number Diff line change
@@ -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`.
4 changes: 2 additions & 2 deletions tests/ui/proc-macro/weird-braces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ trait Bar<const V: bool> {}
#[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() {}
Loading
Loading