mirror of https://github.com/rust-lang/rust.git
Auto merge of #52841 - petrochenkov:premacro, r=alexcrichton
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 https://github.com/rust-lang/rust/issues/52576 Fixes https://github.com/rust-lang/rust/issues/52512 Fixes https://github.com/rust-lang/rust/issues/51277 cc https://github.com/rust-lang/rust/issues/52269
This commit is contained in:
commit
40e4b6ee3d
|
@ -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),
|
||||
|
@ -67,6 +68,7 @@ pub enum Def {
|
|||
|
||||
// Macro namespace
|
||||
Macro(DefId, MacroKind),
|
||||
NonMacroAttr, // e.g. `#[inline]` or `#[rustfmt::skip]`
|
||||
|
||||
GlobalAsm(DefId),
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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",
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
});
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
@ -200,16 +204,11 @@ 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
|
||||
// a local type parameter
|
||||
|
@ -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(),
|
||||
|
@ -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
|
||||
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use {AmbiguityError, CrateLint, Resolver, ResolutionError, resolve_error};
|
||||
use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult};
|
||||
use Namespace::{self, MacroNS};
|
||||
use {AmbiguityError, CrateLint, Resolver, ResolutionError, is_known_tool, resolve_error};
|
||||
use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, ToNameBinding};
|
||||
use Namespace::{self, TypeNS, MacroNS};
|
||||
use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
|
||||
use resolve_imports::ImportResolver;
|
||||
use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex,
|
||||
|
@ -27,7 +27,7 @@ use syntax::ext::expand::{self, AstFragment, AstFragmentKind, Invocation, Invoca
|
|||
use syntax::ext::hygiene::{self, Mark};
|
||||
use syntax::ext::placeholders::placeholder;
|
||||
use syntax::ext::tt::macro_rules;
|
||||
use syntax::feature_gate::{self, emit_feature_err, GateIssue};
|
||||
use syntax::feature_gate::{self, feature_err, emit_feature_err, is_builtin_attr_name, GateIssue};
|
||||
use syntax::fold::{self, Folder};
|
||||
use syntax::parse::parser::PathStyle;
|
||||
use syntax::parse::token::{self, Token};
|
||||
|
@ -326,6 +326,18 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||
if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
|
||||
self.report_proc_macro_stub(invoc.span());
|
||||
return Err(Determinacy::Determined);
|
||||
} else if let Def::NonMacroAttr = def {
|
||||
if let InvocationKind::Attr { .. } = invoc.kind {
|
||||
if !self.session.features_untracked().tool_attributes {
|
||||
feature_err(&self.session.parse_sess, "tool_attributes",
|
||||
invoc.span(), GateIssue::Language,
|
||||
"tool attributes are unstable").emit();
|
||||
}
|
||||
return Ok(Some(Lrc::new(SyntaxExtension::NonMacroAttr)));
|
||||
} else {
|
||||
self.report_non_macro_attr(invoc.path_span());
|
||||
return Err(Determinacy::Determined);
|
||||
}
|
||||
}
|
||||
let def_id = def.def_id();
|
||||
|
||||
|
@ -348,6 +360,9 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||
if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
|
||||
self.report_proc_macro_stub(path.span);
|
||||
return Err(Determinacy::Determined);
|
||||
} else if let Def::NonMacroAttr = def {
|
||||
self.report_non_macro_attr(path.span);
|
||||
return Err(Determinacy::Determined);
|
||||
}
|
||||
self.unused_macros.remove(&def.def_id());
|
||||
Ok(self.get_macro(def))
|
||||
|
@ -378,6 +393,11 @@ impl<'a> Resolver<'a> {
|
|||
"can't use a procedural macro from the same crate that defines it");
|
||||
}
|
||||
|
||||
fn report_non_macro_attr(&self, span: Span) {
|
||||
self.session.span_err(span,
|
||||
"expected a macro, found non-macro attribute");
|
||||
}
|
||||
|
||||
fn resolve_invoc_to_def(&mut self, invoc: &mut Invocation, scope: Mark, force: bool)
|
||||
-> Result<Def, Determinacy> {
|
||||
let (attr, traits, item) = match invoc.kind {
|
||||
|
@ -450,7 +470,15 @@ impl<'a> Resolver<'a> {
|
|||
|
||||
fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
|
||||
-> Result<Def, Determinacy> {
|
||||
if kind != MacroKind::Bang && path.segments.len() > 1 {
|
||||
let def = self.resolve_macro_to_def_inner(scope, path, kind, force);
|
||||
if def != Err(Determinacy::Undetermined) {
|
||||
// Do not report duplicated errors on every undetermined resolution.
|
||||
path.segments.iter().find(|segment| segment.args.is_some()).map(|segment| {
|
||||
self.session.span_err(segment.args.as_ref().unwrap().span(),
|
||||
"generic arguments in macro path");
|
||||
});
|
||||
}
|
||||
if kind != MacroKind::Bang && path.segments.len() > 1 && def != Ok(Def::NonMacroAttr) {
|
||||
if !self.session.features_untracked().proc_macro_path_invoc {
|
||||
emit_feature_err(
|
||||
&self.session.parse_sess,
|
||||
|
@ -462,15 +490,6 @@ impl<'a> Resolver<'a> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
let def = self.resolve_macro_to_def_inner(scope, path, kind, force);
|
||||
if def != Err(Determinacy::Undetermined) {
|
||||
// Do not report duplicated errors on every undetermined resolution.
|
||||
path.segments.iter().find(|segment| segment.args.is_some()).map(|segment| {
|
||||
self.session.span_err(segment.args.as_ref().unwrap().span(),
|
||||
"generic arguments in macro path");
|
||||
});
|
||||
}
|
||||
def
|
||||
}
|
||||
|
||||
|
@ -544,67 +563,226 @@ impl<'a> Resolver<'a> {
|
|||
result
|
||||
}
|
||||
|
||||
// Resolve the initial segment of a non-global macro path (e.g. `foo` in `foo::bar!();`)
|
||||
// Resolve the initial segment of a non-global macro path
|
||||
// (e.g. `foo` in `foo::bar!(); or `foo!();`).
|
||||
// This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during
|
||||
// expansion and import resolution (perhaps they can be merged in the future).
|
||||
pub fn resolve_lexical_macro_path_segment(&mut self,
|
||||
mut ident: Ident,
|
||||
ns: Namespace,
|
||||
record_used: bool,
|
||||
path_span: Span)
|
||||
-> Result<MacroBinding<'a>, Determinacy> {
|
||||
ident = ident.modern();
|
||||
let mut module = Some(self.current_module);
|
||||
let mut potential_illegal_shadower = Err(Determinacy::Determined);
|
||||
let determinacy =
|
||||
if record_used { Determinacy::Determined } else { Determinacy::Undetermined };
|
||||
loop {
|
||||
let orig_current_module = self.current_module;
|
||||
let result = if let Some(module) = module {
|
||||
self.current_module = module; // Lexical resolutions can never be a privacy error.
|
||||
// Since expanded macros may not shadow the lexical scope and
|
||||
// globs may not shadow global macros (both enforced below),
|
||||
// we resolve with restricted shadowing (indicated by the penultimate argument).
|
||||
self.resolve_ident_in_module_unadjusted(
|
||||
module, ident, ns, true, record_used, path_span,
|
||||
).map(MacroBinding::Modern)
|
||||
} else {
|
||||
self.macro_prelude.get(&ident.name).cloned().ok_or(determinacy)
|
||||
.map(MacroBinding::Global)
|
||||
};
|
||||
self.current_module = orig_current_module;
|
||||
// General principles:
|
||||
// 1. Not controlled (user-defined) names should have higher priority than controlled names
|
||||
// built into the language or standard library. This way we can add new names into the
|
||||
// language or standard library without breaking user code.
|
||||
// 2. "Closed set" below means new names can appear after the current resolution attempt.
|
||||
// Places to search (in order of decreasing priority):
|
||||
// (Type NS)
|
||||
// 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet
|
||||
// (open set, not controlled).
|
||||
// 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
|
||||
// (open, not controlled).
|
||||
// 3. Extern prelude (closed, not controlled).
|
||||
// 4. Tool modules (closed, controlled right now, but not in the future).
|
||||
// 5. Standard library prelude (de-facto closed, controlled).
|
||||
// 6. Language prelude (closed, controlled).
|
||||
// (Macro NS)
|
||||
// 1. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
|
||||
// (open, not controlled).
|
||||
// 2. Macro prelude (language, standard library, user-defined legacy plugins lumped into
|
||||
// one set) (open, the open part is from macro expansions, not controlled).
|
||||
// 2a. User-defined prelude from macro-use
|
||||
// (open, the open part is from macro expansions, not controlled).
|
||||
// 2b. Standard library prelude, currently just a macro-use (closed, controlled)
|
||||
// 2c. Language prelude, perhaps including builtin attributes
|
||||
// (closed, controlled, except for legacy plugins).
|
||||
// 3. Builtin attributes (closed, controlled).
|
||||
|
||||
match result.map(MacroBinding::binding) {
|
||||
Ok(binding) => {
|
||||
if !record_used {
|
||||
return result;
|
||||
assert!(ns == TypeNS || ns == MacroNS);
|
||||
ident = ident.modern();
|
||||
|
||||
// Names from inner scope that can't shadow names from outer scopes, e.g.
|
||||
// mod m { ... }
|
||||
// {
|
||||
// use prefix::*; // if this imports another `m`, then it can't shadow the outer `m`
|
||||
// // and we have and ambiguity error
|
||||
// m::mac!();
|
||||
// }
|
||||
// This includes names from globs and from macro expansions.
|
||||
let mut potentially_ambiguous_result: Option<MacroBinding> = None;
|
||||
|
||||
enum WhereToResolve<'a> {
|
||||
Module(Module<'a>),
|
||||
MacroPrelude,
|
||||
BuiltinAttrs,
|
||||
ExternPrelude,
|
||||
ToolPrelude,
|
||||
StdLibPrelude,
|
||||
PrimitiveTypes,
|
||||
}
|
||||
if let Ok(MacroBinding::Modern(shadower)) = potential_illegal_shadower {
|
||||
if shadower.def() != binding.def() {
|
||||
let name = ident.name;
|
||||
|
||||
// Go through all the scopes and try to resolve the name.
|
||||
let mut where_to_resolve = WhereToResolve::Module(self.current_module);
|
||||
let mut use_prelude = !self.current_module.no_implicit_prelude;
|
||||
loop {
|
||||
let result = match where_to_resolve {
|
||||
WhereToResolve::Module(module) => {
|
||||
let orig_current_module = mem::replace(&mut self.current_module, module);
|
||||
let binding = self.resolve_ident_in_module_unadjusted(
|
||||
module, ident, ns, true, record_used, path_span,
|
||||
);
|
||||
self.current_module = orig_current_module;
|
||||
binding.map(MacroBinding::Modern)
|
||||
}
|
||||
WhereToResolve::MacroPrelude => {
|
||||
match self.macro_prelude.get(&ident.name).cloned() {
|
||||
Some(binding) => Ok(MacroBinding::Global(binding)),
|
||||
None => Err(Determinacy::Determined),
|
||||
}
|
||||
}
|
||||
WhereToResolve::BuiltinAttrs => {
|
||||
if is_builtin_attr_name(ident.name) {
|
||||
let binding = (Def::NonMacroAttr, ty::Visibility::Public,
|
||||
ident.span, Mark::root()).to_name_binding(self.arenas);
|
||||
Ok(MacroBinding::Global(binding))
|
||||
} else {
|
||||
Err(Determinacy::Determined)
|
||||
}
|
||||
}
|
||||
WhereToResolve::ExternPrelude => {
|
||||
if use_prelude && self.extern_prelude.contains(&ident.name) {
|
||||
if !self.session.features_untracked().extern_prelude &&
|
||||
!self.ignore_extern_prelude_feature {
|
||||
feature_err(&self.session.parse_sess, "extern_prelude",
|
||||
ident.span, GateIssue::Language,
|
||||
"access to extern crates through prelude is experimental")
|
||||
.emit();
|
||||
}
|
||||
|
||||
let crate_id =
|
||||
self.crate_loader.process_path_extern(ident.name, ident.span);
|
||||
let crate_root =
|
||||
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
|
||||
self.populate_module_if_necessary(crate_root);
|
||||
|
||||
let binding = (crate_root, ty::Visibility::Public,
|
||||
ident.span, Mark::root()).to_name_binding(self.arenas);
|
||||
Ok(MacroBinding::Global(binding))
|
||||
} else {
|
||||
Err(Determinacy::Determined)
|
||||
}
|
||||
}
|
||||
WhereToResolve::ToolPrelude => {
|
||||
if use_prelude && is_known_tool(ident.name) {
|
||||
let binding = (Def::ToolMod, ty::Visibility::Public,
|
||||
ident.span, Mark::root()).to_name_binding(self.arenas);
|
||||
Ok(MacroBinding::Global(binding))
|
||||
} else {
|
||||
Err(Determinacy::Determined)
|
||||
}
|
||||
}
|
||||
WhereToResolve::StdLibPrelude => {
|
||||
let mut result = Err(Determinacy::Determined);
|
||||
if use_prelude {
|
||||
if let Some(prelude) = self.prelude {
|
||||
if let Ok(binding) =
|
||||
self.resolve_ident_in_module_unadjusted(prelude, ident, ns,
|
||||
false, false, path_span) {
|
||||
result = Ok(MacroBinding::Global(binding));
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
WhereToResolve::PrimitiveTypes => {
|
||||
if let Some(prim_ty) =
|
||||
self.primitive_type_table.primitive_types.get(&ident.name).cloned() {
|
||||
let binding = (Def::PrimTy(prim_ty), ty::Visibility::Public,
|
||||
ident.span, Mark::root()).to_name_binding(self.arenas);
|
||||
Ok(MacroBinding::Global(binding))
|
||||
} else {
|
||||
Err(Determinacy::Determined)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
macro_rules! continue_search { () => {
|
||||
where_to_resolve = match where_to_resolve {
|
||||
WhereToResolve::Module(module) => {
|
||||
match self.hygienic_lexical_parent(module, &mut ident.span) {
|
||||
Some(parent_module) => WhereToResolve::Module(parent_module),
|
||||
None => {
|
||||
use_prelude = !module.no_implicit_prelude;
|
||||
if ns == MacroNS {
|
||||
WhereToResolve::MacroPrelude
|
||||
} else {
|
||||
WhereToResolve::ExternPrelude
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
WhereToResolve::MacroPrelude => WhereToResolve::BuiltinAttrs,
|
||||
WhereToResolve::BuiltinAttrs => break, // nowhere else to search
|
||||
WhereToResolve::ExternPrelude => WhereToResolve::ToolPrelude,
|
||||
WhereToResolve::ToolPrelude => WhereToResolve::StdLibPrelude,
|
||||
WhereToResolve::StdLibPrelude => WhereToResolve::PrimitiveTypes,
|
||||
WhereToResolve::PrimitiveTypes => break, // nowhere else to search
|
||||
};
|
||||
|
||||
continue;
|
||||
}}
|
||||
|
||||
match result {
|
||||
Ok(result) => {
|
||||
if !record_used {
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
let binding = result.binding();
|
||||
|
||||
// Found a solution that is ambiguous with a previously found solution.
|
||||
// Push an ambiguity error for later reporting and
|
||||
// return something for better recovery.
|
||||
if let Some(previous_result) = potentially_ambiguous_result {
|
||||
if binding.def() != previous_result.binding().def() {
|
||||
self.ambiguity_errors.push(AmbiguityError {
|
||||
span: path_span,
|
||||
name,
|
||||
b1: shadower,
|
||||
name: ident.name,
|
||||
b1: previous_result.binding(),
|
||||
b2: binding,
|
||||
lexical: true,
|
||||
});
|
||||
return potential_illegal_shadower;
|
||||
return Ok(previous_result);
|
||||
}
|
||||
}
|
||||
if binding.is_glob_import() || binding.expansion != Mark::root() {
|
||||
potential_illegal_shadower = result;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
},
|
||||
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
|
||||
Err(Determinacy::Determined) => {}
|
||||
}
|
||||
|
||||
module = match module {
|
||||
Some(module) => self.hygienic_lexical_parent(module, &mut ident.span),
|
||||
None => return potential_illegal_shadower,
|
||||
// Found a solution that's not an ambiguity yet, but is "suspicious" and
|
||||
// can participate in ambiguities later on.
|
||||
// Remember it and go search for other solutions in outer scopes.
|
||||
if binding.is_glob_import() || binding.expansion != Mark::root() {
|
||||
potentially_ambiguous_result = Some(result);
|
||||
|
||||
continue_search!();
|
||||
}
|
||||
|
||||
// Found a solution that can't be ambiguous, great success.
|
||||
return Ok(result);
|
||||
},
|
||||
Err(Determinacy::Determined) => {
|
||||
continue_search!();
|
||||
}
|
||||
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
|
||||
}
|
||||
}
|
||||
|
||||
// Previously found potentially ambiguous result turned out to not be ambiguous after all.
|
||||
if let Some(previous_result) = potentially_ambiguous_result {
|
||||
return Ok(previous_result);
|
||||
}
|
||||
|
||||
if record_used { Err(Determinacy::Determined) } else { Err(Determinacy::Undetermined) }
|
||||
}
|
||||
|
||||
pub fn resolve_legacy_scope(&mut self,
|
||||
|
|
|
@ -811,6 +811,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
|
|||
HirDef::Label(..) |
|
||||
HirDef::Macro(..) |
|
||||
HirDef::GlobalAsm(..) |
|
||||
HirDef::ToolMod |
|
||||
HirDef::NonMacroAttr |
|
||||
HirDef::Err => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,17 +65,8 @@ pub fn is_known(attr: &Attribute) -> bool {
|
|||
})
|
||||
}
|
||||
|
||||
const RUST_KNOWN_TOOL: &[&str] = &["clippy", "rustfmt"];
|
||||
const RUST_KNOWN_LINT_TOOL: &[&str] = &["clippy"];
|
||||
|
||||
pub fn is_known_tool(attr: &Attribute) -> bool {
|
||||
let tool_name =
|
||||
attr.path.segments.iter().next().expect("empty path in attribute").ident.name;
|
||||
RUST_KNOWN_TOOL.contains(&tool_name.as_str().as_ref())
|
||||
}
|
||||
|
||||
pub fn is_known_lint_tool(m_item: Ident) -> bool {
|
||||
RUST_KNOWN_LINT_TOOL.contains(&m_item.as_str().as_ref())
|
||||
["clippy"].contains(&m_item.as_str().as_ref())
|
||||
}
|
||||
|
||||
impl NestedMetaItem {
|
||||
|
@ -221,10 +212,6 @@ impl Attribute {
|
|||
pub fn is_value_str(&self) -> bool {
|
||||
self.value_str().is_some()
|
||||
}
|
||||
|
||||
pub fn is_scoped(&self) -> bool {
|
||||
self.path.segments.len() > 1
|
||||
}
|
||||
}
|
||||
|
||||
impl MetaItem {
|
||||
|
|
|
@ -588,6 +588,9 @@ impl MacroKind {
|
|||
|
||||
/// An enum representing the different kinds of syntax extensions.
|
||||
pub enum SyntaxExtension {
|
||||
/// A trivial "extension" that does nothing, only keeps the attribute and marks it as known.
|
||||
NonMacroAttr,
|
||||
|
||||
/// A syntax extension that is attached to an item and creates new items
|
||||
/// based upon it.
|
||||
///
|
||||
|
@ -667,6 +670,7 @@ impl SyntaxExtension {
|
|||
SyntaxExtension::IdentTT(..) |
|
||||
SyntaxExtension::ProcMacro { .. } =>
|
||||
MacroKind::Bang,
|
||||
SyntaxExtension::NonMacroAttr |
|
||||
SyntaxExtension::MultiDecorator(..) |
|
||||
SyntaxExtension::MultiModifier(..) |
|
||||
SyntaxExtension::AttrProcMacro(..) =>
|
||||
|
@ -696,6 +700,7 @@ impl SyntaxExtension {
|
|||
SyntaxExtension::AttrProcMacro(.., edition) |
|
||||
SyntaxExtension::ProcMacroDerive(.., edition) => edition,
|
||||
// Unstable legacy stuff
|
||||
SyntaxExtension::NonMacroAttr |
|
||||
SyntaxExtension::IdentTT(..) |
|
||||
SyntaxExtension::MultiDecorator(..) |
|
||||
SyntaxExtension::MultiModifier(..) |
|
||||
|
|
|
@ -37,7 +37,7 @@ use visit::{self, Visitor};
|
|||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::mem;
|
||||
use std::{iter, mem};
|
||||
use std::rc::Rc;
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
@ -244,6 +244,15 @@ impl Invocation {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn path_span(&self) -> Span {
|
||||
match self.kind {
|
||||
InvocationKind::Bang { ref mac, .. } => mac.node.path.span,
|
||||
InvocationKind::Attr { attr: Some(ref attr), .. } => attr.path.span,
|
||||
InvocationKind::Attr { attr: None, .. } => DUMMY_SP,
|
||||
InvocationKind::Derive { ref path, .. } => path.span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn attr_id(&self) -> Option<ast::AttrId> {
|
||||
match self.kind {
|
||||
InvocationKind::Attr { attr: Some(ref attr), .. } => Some(attr.id),
|
||||
|
@ -568,6 +577,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
});
|
||||
|
||||
match *ext {
|
||||
NonMacroAttr => {
|
||||
attr::mark_known(&attr);
|
||||
let item = item.map_attrs(|mut attrs| { attrs.push(attr); attrs });
|
||||
Some(invoc.fragment_kind.expect_from_annotatables(iter::once(item)))
|
||||
}
|
||||
MultiModifier(ref mac) => {
|
||||
let meta = attr.parse_meta(self.cx.parse_sess)
|
||||
.map_err(|mut e| { e.emit(); }).ok()?;
|
||||
|
@ -812,7 +826,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
MultiDecorator(..) | MultiModifier(..) | AttrProcMacro(..) => {
|
||||
MultiDecorator(..) | MultiModifier(..) |
|
||||
AttrProcMacro(..) | SyntaxExtension::NonMacroAttr => {
|
||||
self.cx.span_err(path.span,
|
||||
&format!("`{}` can only be used in attributes", path));
|
||||
self.cx.trace_macros_diag();
|
||||
|
@ -1669,13 +1684,16 @@ impl<'feat> ExpansionConfig<'feat> {
|
|||
fn enable_allow_internal_unstable = allow_internal_unstable,
|
||||
fn enable_custom_derive = custom_derive,
|
||||
fn enable_format_args_nl = format_args_nl,
|
||||
fn use_extern_macros_enabled = use_extern_macros,
|
||||
fn macros_in_extern_enabled = macros_in_extern,
|
||||
fn proc_macro_mod = proc_macro_mod,
|
||||
fn proc_macro_gen = proc_macro_gen,
|
||||
fn proc_macro_expr = proc_macro_expr,
|
||||
fn proc_macro_non_items = proc_macro_non_items,
|
||||
}
|
||||
|
||||
pub fn use_extern_macros_enabled(&self) -> bool {
|
||||
self.features.map_or(false, |features| features.use_extern_macros())
|
||||
}
|
||||
}
|
||||
|
||||
// A Marker adds the given mark to the syntax context.
|
||||
|
|
|
@ -80,6 +80,11 @@ macro_rules! declare_features {
|
|||
{
|
||||
$(f(stringify!($feature), self.$feature);)+
|
||||
}
|
||||
|
||||
pub fn use_extern_macros(&self) -> bool {
|
||||
// The `decl_macro` and `tool_attributes` features imply `use_extern_macros`.
|
||||
self.use_extern_macros || self.decl_macro || self.tool_attributes
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -689,6 +694,10 @@ pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType, Att
|
|||
BUILTIN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
|
||||
}
|
||||
|
||||
pub fn is_builtin_attr_name(name: ast::Name) -> bool {
|
||||
BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| name == builtin_name)
|
||||
}
|
||||
|
||||
pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
|
||||
BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name)) ||
|
||||
attr.name().as_str().starts_with("rustc_")
|
||||
|
@ -1198,28 +1207,9 @@ impl<'a> Context<'a> {
|
|||
// before the plugin attributes are registered
|
||||
// so we skip this then
|
||||
if !is_macro {
|
||||
if attr.is_scoped() {
|
||||
gate_feature!(self, tool_attributes, attr.span,
|
||||
&format!("scoped attribute `{}` is experimental", attr.path));
|
||||
if attr::is_known_tool(attr) {
|
||||
attr::mark_used(attr);
|
||||
} else {
|
||||
span_err!(
|
||||
self.parse_sess.span_diagnostic,
|
||||
attr.span,
|
||||
E0694,
|
||||
"an unknown tool name found in scoped attribute: `{}`.",
|
||||
attr.path
|
||||
);
|
||||
}
|
||||
} else {
|
||||
gate_feature!(self, custom_attribute, attr.span,
|
||||
&format!("The attribute `{}` is currently \
|
||||
unknown to the compiler and \
|
||||
may have meaning \
|
||||
added to it in the future",
|
||||
attr.path));
|
||||
}
|
||||
let msg = format!("The attribute `{}` is currently unknown to the compiler and \
|
||||
may have meaning added to it in the future", attr.path);
|
||||
gate_feature!(self, custom_attribute, attr.span, &msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1529,7 +1519,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
if self.context.features.use_extern_macros && attr::is_known(attr) {
|
||||
if self.context.features.use_extern_macros() && attr::is_known(attr) {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -2004,7 +1994,7 @@ impl FeatureChecker {
|
|||
// the branching can be eliminated by modifying `set!()` to set these spans
|
||||
// only for the features that need to be checked for mutual exclusion.
|
||||
fn collect(&mut self, features: &Features, span: Span) {
|
||||
if features.use_extern_macros {
|
||||
if features.use_extern_macros() {
|
||||
// If self.use_extern_macros is None, set to Some(span)
|
||||
self.use_extern_macros = self.use_extern_macros.or(Some(span));
|
||||
}
|
||||
|
|
|
@ -8,9 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(tool_attributes)]
|
||||
#![feature(use_extern_macros, proc_macro_path_invoc)]
|
||||
|
||||
#![foo::bar] //~ ERROR an unknown tool name found in scoped attribute: `foo::bar`. [E0694]
|
||||
|
||||
#[foo::bar] //~ ERROR an unknown tool name found in scoped attribute: `foo::bar`. [E0694]
|
||||
#[foo::bar] //~ ERROR failed to resolve. Use of undeclared type or module `foo`
|
||||
fn main() {}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// aux-build:issue-42708.rs
|
||||
// ignore-stage1
|
||||
|
||||
#![feature(decl_macro, use_extern_macros, proc_macro_path_invoc)]
|
||||
#![feature(decl_macro, proc_macro_path_invoc)]
|
||||
#![allow(unused)]
|
||||
|
||||
extern crate issue_42708;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// aux-build:issue-50061.rs
|
||||
// ignore-stage1
|
||||
|
||||
#![feature(use_extern_macros, proc_macro_path_invoc, decl_macro)]
|
||||
#![feature(proc_macro_path_invoc, decl_macro)]
|
||||
|
||||
extern crate issue_50061;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// aux-build:parent-source-spans.rs
|
||||
// ignore-stage1
|
||||
|
||||
#![feature(use_extern_macros, decl_macro, proc_macro_non_items)]
|
||||
#![feature(decl_macro, proc_macro_non_items)]
|
||||
|
||||
extern crate parent_source_spans;
|
||||
|
||||
|
|
|
@ -12,3 +12,8 @@
|
|||
macro_rules! mac {
|
||||
($ident:ident) => { let $ident = 42; }
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! inline {
|
||||
() => ()
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error[E0658]: macro invocations in `extern {}` blocks are experimental. (see issue #49476)
|
||||
error[E0658]: macro and proc-macro invocations in `extern {}` blocks are experimental. (see issue #49476)
|
||||
--> $DIR/feature-gate-macros_in_extern.rs:29:5
|
||||
|
|
||||
LL | returns_isize!(rust_get_test_int);
|
||||
|
@ -6,7 +6,7 @@ LL | returns_isize!(rust_get_test_int);
|
|||
|
|
||||
= help: add #![feature(macros_in_extern)] to the crate attributes to enable
|
||||
|
||||
error[E0658]: macro invocations in `extern {}` blocks are experimental. (see issue #49476)
|
||||
error[E0658]: macro and proc-macro invocations in `extern {}` blocks are experimental. (see issue #49476)
|
||||
--> $DIR/feature-gate-macros_in_extern.rs:31:5
|
||||
|
|
||||
LL | takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
|
||||
|
@ -14,7 +14,7 @@ LL | takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
|
|||
|
|
||||
= help: add #![feature(macros_in_extern)] to the crate attributes to enable
|
||||
|
||||
error[E0658]: macro invocations in `extern {}` blocks are experimental. (see issue #49476)
|
||||
error[E0658]: macro and proc-macro invocations in `extern {}` blocks are experimental. (see issue #49476)
|
||||
--> $DIR/feature-gate-macros_in_extern.rs:33:5
|
||||
|
|
||||
LL | emits_nothing!();
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
fn main() {
|
||||
#[rustfmt::skip] //~ ERROR scoped attribute `rustfmt::skip` is experimental
|
||||
#[rustfmt::skip] //~ ERROR tool attributes are unstable
|
||||
let x = 3
|
||||
;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
error[E0658]: scoped attribute `rustfmt::skip` is experimental (see issue #44690)
|
||||
--> $DIR/feature-gate-tool_attributes.rs:12:5
|
||||
error[E0658]: tool attributes are unstable (see issue #44690)
|
||||
--> $DIR/feature-gate-tool_attributes.rs:14:5
|
||||
|
|
||||
LL | #[rustfmt::skip] //~ ERROR scoped attribute `rustfmt::skip` is experimental
|
||||
LL | #[rustfmt::skip] //~ ERROR tool attributes are unstable
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add #![feature(tool_attributes)] to the crate attributes to enable
|
||||
|
|
|
@ -9,6 +9,6 @@
|
|||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
print!(test!());
|
||||
print!(testo!());
|
||||
//~^ ERROR: format argument must be a string literal
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
error: format argument must be a string literal
|
||||
--> $DIR/issue-11692-1.rs:12:12
|
||||
|
|
||||
LL | print!(test!());
|
||||
| ^^^^^^^
|
||||
LL | print!(testo!());
|
||||
| ^^^^^^^^
|
||||
help: you might be missing a string literal to format with
|
||||
|
|
||||
LL | print!("{}", test!());
|
||||
LL | print!("{}", testo!());
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
|
@ -10,5 +10,5 @@
|
|||
|
||||
fn main() {
|
||||
concat!(test!());
|
||||
//~^ ERROR cannot find macro `test!` in this scope
|
||||
//~^ ERROR expected a macro, found non-macro attribute
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error: cannot find macro `test!` in this scope
|
||||
error: expected a macro, found non-macro attribute
|
||||
--> $DIR/issue-11692-2.rs:12:13
|
||||
|
|
||||
LL | concat!(test!());
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
// compile-pass
|
||||
|
||||
#![feature(use_extern_macros, decl_macro)]
|
||||
#![feature(decl_macro)]
|
||||
|
||||
mod type_ns {
|
||||
pub type A = u8;
|
||||
|
|
|
@ -8,11 +8,13 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Make sure that 'custom_attributes' feature does not allow scoped attributes.
|
||||
#![feature(use_extern_macros, extern_prelude)]
|
||||
|
||||
#![feature(custom_attributes)]
|
||||
mod m {
|
||||
fn check() {
|
||||
Vec::clone!(); //~ ERROR failed to resolve. Not a module `Vec`
|
||||
u8::clone!(); //~ ERROR failed to resolve. Not a module `u8`
|
||||
}
|
||||
}
|
||||
|
||||
#[foo::bar]
|
||||
//~^ ERROR scoped attribute `foo::bar` is experimental (see issue #44690) [E0658]
|
||||
//~^^ ERROR an unknown tool name found in scoped attribute: `foo::bar`. [E0694]
|
||||
fn main() {}
|
|
@ -0,0 +1,15 @@
|
|||
error[E0433]: failed to resolve. Not a module `Vec`
|
||||
--> $DIR/macro-path-prelude-fail-1.rs:15:9
|
||||
|
|
||||
LL | Vec::clone!(); //~ ERROR failed to resolve. Not a module `Vec`
|
||||
| ^^^ Not a module `Vec`
|
||||
|
||||
error[E0433]: failed to resolve. Not a module `u8`
|
||||
--> $DIR/macro-path-prelude-fail-1.rs:16:9
|
||||
|
|
||||
LL | u8::clone!(); //~ ERROR failed to resolve. Not a module `u8`
|
||||
| ^^ Not a module `u8`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2018 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
mod m {
|
||||
fn check() {
|
||||
Result::Ok!(); //~ ERROR fail to resolve non-ident macro path
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,8 @@
|
|||
error: fail to resolve non-ident macro path
|
||||
--> $DIR/macro-path-prelude-fail-2.rs:15:9
|
||||
|
|
||||
LL | Result::Ok!(); //~ ERROR fail to resolve non-ident macro path
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2018 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
#[derive(inline)] //~ ERROR expected a macro, found non-macro attribute
|
||||
struct S;
|
||||
|
||||
fn main() {
|
||||
inline!(); //~ ERROR expected a macro, found non-macro attribute
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
error: expected a macro, found non-macro attribute
|
||||
--> $DIR/macro-path-prelude-fail-3.rs:13:10
|
||||
|
|
||||
LL | #[derive(inline)] //~ ERROR expected a macro, found non-macro attribute
|
||||
| ^^^^^^
|
||||
|
||||
error: expected a macro, found non-macro attribute
|
||||
--> $DIR/macro-path-prelude-fail-3.rs:17:5
|
||||
|
|
||||
LL | inline!(); //~ ERROR expected a macro, found non-macro attribute
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -8,8 +8,14 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
#[rustfmt::skip] //~ ERROR scoped attribute `rustfmt::skip` is experimental
|
||||
let x =
|
||||
3;
|
||||
// compile-pass
|
||||
|
||||
#![feature(use_extern_macros, extern_prelude)]
|
||||
|
||||
mod m {
|
||||
fn check() {
|
||||
std::panic!(); // OK
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2018 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:macro-in-other-crate.rs
|
||||
|
||||
#![feature(decl_macro, extern_prelude)]
|
||||
|
||||
macro_rules! add_macro_expanded_things_to_macro_prelude {() => {
|
||||
#[macro_use]
|
||||
extern crate macro_in_other_crate;
|
||||
}}
|
||||
|
||||
add_macro_expanded_things_to_macro_prelude!();
|
||||
|
||||
mod m1 {
|
||||
fn check() {
|
||||
inline!(); //~ ERROR `inline` is ambiguous
|
||||
}
|
||||
}
|
||||
|
||||
mod m2 {
|
||||
pub mod std {
|
||||
pub macro panic() {}
|
||||
}
|
||||
}
|
||||
|
||||
mod m3 {
|
||||
use m2::*; // glob-import user-defined `std`
|
||||
fn check() {
|
||||
std::panic!(); //~ ERROR `std` is ambiguous
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,42 @@
|
|||
error[E0659]: `inline` is ambiguous
|
||||
--> $DIR/macro-path-prelude-shadowing.rs:24:9
|
||||
|
|
||||
LL | inline!(); //~ ERROR `inline` is ambiguous
|
||||
| ^^^^^^
|
||||
|
|
||||
note: `inline` could refer to the name imported here
|
||||
--> $DIR/macro-path-prelude-shadowing.rs:16:5
|
||||
|
|
||||
LL | #[macro_use]
|
||||
| ^^^^^^^^^^^^
|
||||
...
|
||||
LL | add_macro_expanded_things_to_macro_prelude!();
|
||||
| ---------------------------------------------- in this macro invocation
|
||||
note: `inline` could also refer to the name defined here
|
||||
--> $DIR/macro-path-prelude-shadowing.rs:24:9
|
||||
|
|
||||
LL | inline!(); //~ ERROR `inline` is ambiguous
|
||||
| ^^^^^^
|
||||
= note: macro-expanded macro imports do not shadow
|
||||
|
||||
error[E0659]: `std` is ambiguous
|
||||
--> $DIR/macro-path-prelude-shadowing.rs:37:9
|
||||
|
|
||||
LL | std::panic!(); //~ ERROR `std` is ambiguous
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: `std` could refer to the name imported here
|
||||
--> $DIR/macro-path-prelude-shadowing.rs:35:9
|
||||
|
|
||||
LL | use m2::*; // glob-import user-defined `std`
|
||||
| ^^^^^
|
||||
note: `std` could also refer to the name defined here
|
||||
--> $DIR/macro-path-prelude-shadowing.rs:37:9
|
||||
|
|
||||
LL | std::panic!(); //~ ERROR `std` is ambiguous
|
||||
| ^^^
|
||||
= note: consider adding an explicit import of `std` to disambiguate
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0659`.
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2018 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// If macro modularization (`use_extern_macros`) is not enabled,
|
||||
// then tool attributes are treated as custom attributes.
|
||||
|
||||
#[rustfmt::bar] //~ ERROR The attribute `rustfmt::bar` is currently unknown to the compiler
|
||||
fn main() {}
|
|
@ -0,0 +1,11 @@
|
|||
error[E0658]: The attribute `rustfmt::bar` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
|
||||
--> $DIR/tool-attributes-disabled-1.rs:14:1
|
||||
|
|
||||
LL | #[rustfmt::bar] //~ ERROR The attribute `rustfmt::bar` is currently unknown to the compiler
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add #![feature(custom_attribute)] to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2018 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// If macro modularization (`use_extern_macros`) is not enabled,
|
||||
// then tool attributes are treated as custom attributes.
|
||||
|
||||
// compile-pass
|
||||
|
||||
#![feature(custom_attribute)]
|
||||
|
||||
#[rustfmt::bar]
|
||||
fn main() {}
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright 2018 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(tool_attributes)]
|
||||
|
||||
type A = rustfmt; //~ ERROR expected type, found tool module `rustfmt`
|
||||
type B = rustfmt::skip; //~ ERROR expected type, found non-macro attribute `rustfmt::skip`
|
||||
|
||||
#[derive(rustfmt)] //~ ERROR cannot find derive macro `rustfmt` in this scope
|
||||
struct S;
|
||||
|
||||
#[rustfmt] //~ ERROR cannot find attribute macro `rustfmt` in this scope
|
||||
fn check() {}
|
||||
|
||||
#[rustfmt::skip] // OK
|
||||
fn main() {
|
||||
rustfmt; //~ ERROR expected value, found tool module `rustfmt`
|
||||
rustfmt!(); //~ ERROR cannot find macro `rustfmt!` in this scope
|
||||
|
||||
rustfmt::skip; //~ ERROR expected value, found non-macro attribute `rustfmt::skip`
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
error: cannot find derive macro `rustfmt` in this scope
|
||||
--> $DIR/tool-attributes-misplaced-1.rs:16:10
|
||||
|
|
||||
LL | #[derive(rustfmt)] //~ ERROR cannot find derive macro `rustfmt` in this scope
|
||||
| ^^^^^^^
|
||||
|
||||
error: cannot find attribute macro `rustfmt` in this scope
|
||||
--> $DIR/tool-attributes-misplaced-1.rs:19:3
|
||||
|
|
||||
LL | #[rustfmt] //~ ERROR cannot find attribute macro `rustfmt` in this scope
|
||||
| ^^^^^^^
|
||||
|
||||
error: cannot find macro `rustfmt!` in this scope
|
||||
--> $DIR/tool-attributes-misplaced-1.rs:25:5
|
||||
|
|
||||
LL | rustfmt!(); //~ ERROR cannot find macro `rustfmt!` in this scope
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0573]: expected type, found tool module `rustfmt`
|
||||
--> $DIR/tool-attributes-misplaced-1.rs:13:10
|
||||
|
|
||||
LL | type A = rustfmt; //~ ERROR expected type, found tool module `rustfmt`
|
||||
| ^^^^^^^ not a type
|
||||
|
||||
error[E0573]: expected type, found non-macro attribute `rustfmt::skip`
|
||||
--> $DIR/tool-attributes-misplaced-1.rs:14:10
|
||||
|
|
||||
LL | type B = rustfmt::skip; //~ ERROR expected type, found non-macro attribute `rustfmt::skip`
|
||||
| ^^^^^^^^^^^^^ not a type
|
||||
|
||||
error[E0423]: expected value, found tool module `rustfmt`
|
||||
--> $DIR/tool-attributes-misplaced-1.rs:24:5
|
||||
|
|
||||
LL | rustfmt; //~ ERROR expected value, found tool module `rustfmt`
|
||||
| ^^^^^^^ not a value
|
||||
|
||||
error[E0423]: expected value, found non-macro attribute `rustfmt::skip`
|
||||
--> $DIR/tool-attributes-misplaced-1.rs:27:5
|
||||
|
|
||||
LL | rustfmt::skip; //~ ERROR expected value, found non-macro attribute `rustfmt::skip`
|
||||
| ^^^^^^^^^^^^^ not a value
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
Some errors occurred: E0423, E0573.
|
||||
For more information about an error, try `rustc --explain E0423`.
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2018 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(tool_attributes)]
|
||||
|
||||
#[derive(rustfmt::skip)] //~ ERROR expected a macro, found non-macro attribute
|
||||
struct S;
|
||||
|
||||
fn main() {
|
||||
rustfmt::skip!(); //~ ERROR expected a macro, found non-macro attribute
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
error: expected a macro, found non-macro attribute
|
||||
--> $DIR/tool-attributes-misplaced-2.rs:13:10
|
||||
|
|
||||
LL | #[derive(rustfmt::skip)] //~ ERROR expected a macro, found non-macro attribute
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: expected a macro, found non-macro attribute
|
||||
--> $DIR/tool-attributes-misplaced-2.rs:17:5
|
||||
|
|
||||
LL | rustfmt::skip!(); //~ ERROR expected a macro, found non-macro attribute
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2018 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(tool_attributes, proc_macro_path_invoc)]
|
||||
|
||||
mod rustfmt {}
|
||||
|
||||
#[rustfmt::skip] //~ ERROR failed to resolve. Could not find `skip` in `rustfmt`
|
||||
fn main() {}
|
|
@ -0,0 +1,9 @@
|
|||
error[E0433]: failed to resolve. Could not find `skip` in `rustfmt`
|
||||
--> $DIR/tool-attributes-shadowing.rs:15:12
|
||||
|
|
||||
LL | #[rustfmt::skip] //~ ERROR failed to resolve. Could not find `skip` in `rustfmt`
|
||||
| ^^^^ Could not find `skip` in `rustfmt`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
Loading…
Reference in New Issue