Skip to content

Commit

Permalink
Auto merge of #52841 - petrochenkov:premacro, r=alexcrichton
Browse files Browse the repository at this point in the history
resolve: Implement prelude search for macro paths, implement tool attributes

When identifier is macro path is resolved in scopes (i.e. the first path segment - `foo` in `foo::mac!()` or `foo!()`), scopes are searched in the same order as for non-macro paths - items in modules, extern prelude, tool prelude (see later), standard library prelude, language prelude, but with some extra shadowing restrictions (names from globs and macro expansions cannot shadow names from outer scopes). See the comment in `fn resolve_lexical_macro_path_segment` for more details.

"Tool prelude" currently contains two "tool modules" `rustfmt` and `clippy`, and is searched immediately after extern prelude.
This makes the [possible long-term solution](https://github.com/rust-lang/rfcs/blob/master/text/2103-tool-attributes.md#long-term-solution) for tool attributes exactly equivalent to the existing extern prelude scheme, except that `--extern=my_crate` making crate names available in scope is replaced with something like `--tool=my_tool` making tool names available in scope.

The `tool_attributes` feature is still unstable and `#![feature(tool_attributes)]` now implicitly enables `#![feature(use_extern_macros)]`. `use_extern_macros` is a prerequisite for `tool_attributes`, so their stabilization will happen in the same order.
If `use_extern_macros` is not enabled, then tool attributes are treated as custom attributes (this is temporary, anyway).

Fixes #52576
Fixes #52512
Fixes #51277
cc #52269
  • Loading branch information
bors committed Aug 2, 2018
2 parents 40cb447 + c3e5421 commit 40e4b6e
Show file tree
Hide file tree
Showing 42 changed files with 675 additions and 135 deletions.
6 changes: 6 additions & 0 deletions src/librustc/hir/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ pub enum Def {
PrimTy(hir::PrimTy),
TyParam(DefId),
SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),
ToolMod, // e.g. `rustfmt` in `#[rustfmt::skip]`

// Value namespace
Fn(DefId),
Expand All @@ -67,6 +68,7 @@ pub enum Def {

// Macro namespace
Macro(DefId, MacroKind),
NonMacroAttr, // e.g. `#[inline]` or `#[rustfmt::skip]`

GlobalAsm(DefId),

Expand Down Expand Up @@ -259,6 +261,8 @@ impl Def {
Def::Label(..) |
Def::PrimTy(..) |
Def::SelfTy(..) |
Def::ToolMod |
Def::NonMacroAttr |
Def::Err => {
bug!("attempted .def_id() on invalid def: {:?}", self)
}
Expand Down Expand Up @@ -299,6 +303,8 @@ impl Def {
Def::SelfTy(..) => "self type",
Def::Macro(.., macro_kind) => macro_kind.descr(),
Def::GlobalAsm(..) => "global asm",
Def::ToolMod => "tool module",
Def::NonMacroAttr => "non-macro attribute",
Def::Err => "unresolved item",
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/ich/impls_hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1016,6 +1016,8 @@ impl_stable_hash_for!(enum hir::def::Def {
Label(node_id),
Macro(def_id, macro_kind),
GlobalAsm(def_id),
ToolMod,
NonMacroAttr,
Err
});

Expand Down
3 changes: 2 additions & 1 deletion src/librustc_resolve/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,8 @@ impl<'a> Resolver<'a> {
pub fn get_macro(&mut self, def: Def) -> Lrc<SyntaxExtension> {
let def_id = match def {
Def::Macro(def_id, ..) => def_id,
_ => panic!("Expected Def::Macro(..)"),
Def::NonMacroAttr => return Lrc::new(SyntaxExtension::NonMacroAttr),
_ => panic!("Expected Def::Macro(..) or Def::NonMacroAttr"),
};
if let Some(ext) = self.macro_map.get(&def_id) {
return ext.clone();
Expand Down
3 changes: 1 addition & 2 deletions src/librustc_resolve/check_unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,7 @@ pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) {
directive.vis.get() == ty::Visibility::Public ||
directive.span.is_dummy() => {
if let ImportDirectiveSubclass::MacroUse = directive.subclass {
if resolver.session.features_untracked().use_extern_macros &&
!directive.span.is_dummy() {
if resolver.use_extern_macros && !directive.span.is_dummy() {
resolver.session.buffer_lint(
lint::builtin::MACRO_USE_EXTERN_CRATE,
directive.id,
Expand Down
30 changes: 18 additions & 12 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ mod check_unused;
mod build_reduced_graph;
mod resolve_imports;

fn is_known_tool(name: Name) -> bool {
["clippy", "rustfmt"].contains(&&*name.as_str())
}

/// A free importable items suggested in case of resolution failure.
struct ImportSuggestion {
path: Path,
Expand Down Expand Up @@ -200,15 +204,10 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
err.span_label(typaram_span, "type variable from outer function");
}
},
Def::Mod(..) | Def::Struct(..) | Def::Union(..) | Def::Enum(..) | Def::Variant(..) |
Def::Trait(..) | Def::TyAlias(..) | Def::TyForeign(..) | Def::TraitAlias(..) |
Def::AssociatedTy(..) | Def::PrimTy(..) | Def::Fn(..) | Def::Const(..) |
Def::Static(..) | Def::StructCtor(..) | Def::VariantCtor(..) | Def::Method(..) |
Def::AssociatedConst(..) | Def::Local(..) | Def::Upvar(..) | Def::Label(..) |
Def::Existential(..) | Def::AssociatedExistential(..) |
Def::Macro(..) | Def::GlobalAsm(..) | Def::Err =>
_ => {
bug!("TypeParametersFromOuterFunction should only be used with Def::SelfTy or \
Def::TyParam")
}
}

// Try to retrieve the span of the function signature and generate a new message with
Expand Down Expand Up @@ -1711,9 +1710,7 @@ impl<'a> Resolver<'a> {
vis: ty::Visibility::Public,
}),

// The `proc_macro` and `decl_macro` features imply `use_extern_macros`
use_extern_macros:
features.use_extern_macros || features.decl_macro,
use_extern_macros: features.use_extern_macros(),

crate_loader,
macro_names: FxHashSet(),
Expand Down Expand Up @@ -1846,6 +1843,7 @@ impl<'a> Resolver<'a> {
path_span: Span)
-> Option<LexicalScopeBinding<'a>> {
let record_used = record_used_id.is_some();
assert!(ns == TypeNS || ns == ValueNS);
if ns == TypeNS {
ident.span = if ident.name == keywords::SelfType.name() {
// FIXME(jseyfried) improve `Self` hygiene
Expand Down Expand Up @@ -1922,8 +1920,9 @@ impl<'a> Resolver<'a> {
return Some(LexicalScopeBinding::Item(binding))
}
_ if poisoned.is_some() => break,
Err(Undetermined) => return None,
Err(Determined) => {}
Err(Determined) => continue,
Err(Undetermined) =>
span_bug!(ident.span, "undetermined resolution during main resolution pass"),
}
}

Expand All @@ -1945,6 +1944,11 @@ impl<'a> Resolver<'a> {
ident.span, Mark::root()).to_name_binding(self.arenas);
return Some(LexicalScopeBinding::Item(binding));
}
if ns == TypeNS && is_known_tool(ident.name) {
let binding = (Def::ToolMod, ty::Visibility::Public,
ident.span, Mark::root()).to_name_binding(self.arenas);
return Some(LexicalScopeBinding::Item(binding));
}
if let Some(prelude) = self.prelude {
if let Ok(binding) = self.resolve_ident_in_module_unadjusted(prelude, ident, ns,
false, false, path_span) {
Expand Down Expand Up @@ -3505,6 +3509,8 @@ impl<'a> Resolver<'a> {
let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(def);
if let Some(next_module) = binding.module() {
module = Some(next_module);
} else if def == Def::ToolMod && i + 1 != path.len() {
return PathResult::NonModule(PathResolution::new(Def::NonMacroAttr))
} else if def == Def::Err {
return PathResult::NonModule(err_path_resolution());
} else if opt_ns.is_some() && (is_last || maybe_assoc) {
Expand Down
Loading

0 comments on commit 40e4b6e

Please sign in to comment.