resolve: Implement prelude search for macro paths

resolve/expansion: Implement tool attributes
This commit is contained in:
Vadim Petrochenkov 2018-07-23 02:52:51 +03:00
parent c63bb1d6a7
commit c3e54217e8
42 changed files with 683 additions and 143 deletions

View File

@ -49,6 +49,7 @@ pub enum Def {
PrimTy(hir::PrimTy), PrimTy(hir::PrimTy),
TyParam(DefId), TyParam(DefId),
SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */), SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),
ToolMod, // e.g. `rustfmt` in `#[rustfmt::skip]`
// Value namespace // Value namespace
Fn(DefId), Fn(DefId),
@ -67,6 +68,7 @@ pub enum Def {
// Macro namespace // Macro namespace
Macro(DefId, MacroKind), Macro(DefId, MacroKind),
NonMacroAttr, // e.g. `#[inline]` or `#[rustfmt::skip]`
GlobalAsm(DefId), GlobalAsm(DefId),
@ -259,6 +261,8 @@ impl Def {
Def::Label(..) | Def::Label(..) |
Def::PrimTy(..) | Def::PrimTy(..) |
Def::SelfTy(..) | Def::SelfTy(..) |
Def::ToolMod |
Def::NonMacroAttr |
Def::Err => { Def::Err => {
bug!("attempted .def_id() on invalid def: {:?}", self) bug!("attempted .def_id() on invalid def: {:?}", self)
} }
@ -299,6 +303,8 @@ impl Def {
Def::SelfTy(..) => "self type", Def::SelfTy(..) => "self type",
Def::Macro(.., macro_kind) => macro_kind.descr(), Def::Macro(.., macro_kind) => macro_kind.descr(),
Def::GlobalAsm(..) => "global asm", Def::GlobalAsm(..) => "global asm",
Def::ToolMod => "tool module",
Def::NonMacroAttr => "non-macro attribute",
Def::Err => "unresolved item", Def::Err => "unresolved item",
} }
} }

View File

@ -1016,6 +1016,8 @@ impl_stable_hash_for!(enum hir::def::Def {
Label(node_id), Label(node_id),
Macro(def_id, macro_kind), Macro(def_id, macro_kind),
GlobalAsm(def_id), GlobalAsm(def_id),
ToolMod,
NonMacroAttr,
Err Err
}); });

View File

@ -629,7 +629,8 @@ impl<'a> Resolver<'a> {
pub fn get_macro(&mut self, def: Def) -> Lrc<SyntaxExtension> { pub fn get_macro(&mut self, def: Def) -> Lrc<SyntaxExtension> {
let def_id = match def { let def_id = match def {
Def::Macro(def_id, ..) => def_id, 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) { if let Some(ext) = self.macro_map.get(&def_id) {
return ext.clone(); return ext.clone();

View File

@ -131,8 +131,7 @@ pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) {
directive.vis.get() == ty::Visibility::Public || directive.vis.get() == ty::Visibility::Public ||
directive.span.is_dummy() => { directive.span.is_dummy() => {
if let ImportDirectiveSubclass::MacroUse = directive.subclass { if let ImportDirectiveSubclass::MacroUse = directive.subclass {
if resolver.session.features_untracked().use_extern_macros && if resolver.use_extern_macros && !directive.span.is_dummy() {
!directive.span.is_dummy() {
resolver.session.buffer_lint( resolver.session.buffer_lint(
lint::builtin::MACRO_USE_EXTERN_CRATE, lint::builtin::MACRO_USE_EXTERN_CRATE,
directive.id, directive.id,

View File

@ -86,6 +86,10 @@ mod check_unused;
mod build_reduced_graph; mod build_reduced_graph;
mod resolve_imports; 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. /// A free importable items suggested in case of resolution failure.
struct ImportSuggestion { struct ImportSuggestion {
path: Path, path: Path,
@ -200,15 +204,10 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
err.span_label(typaram_span, "type variable from outer function"); 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 \ bug!("TypeParametersFromOuterFunction should only be used with Def::SelfTy or \
Def::TyParam") Def::TyParam")
}
} }
// Try to retrieve the span of the function signature and generate a new message with // Try to retrieve the span of the function signature and generate a new message with
@ -1711,9 +1710,7 @@ impl<'a> Resolver<'a> {
vis: ty::Visibility::Public, vis: ty::Visibility::Public,
}), }),
// The `proc_macro` and `decl_macro` features imply `use_extern_macros` use_extern_macros: features.use_extern_macros(),
use_extern_macros:
features.use_extern_macros || features.decl_macro,
crate_loader, crate_loader,
macro_names: FxHashSet(), macro_names: FxHashSet(),
@ -1846,6 +1843,7 @@ impl<'a> Resolver<'a> {
path_span: Span) path_span: Span)
-> Option<LexicalScopeBinding<'a>> { -> Option<LexicalScopeBinding<'a>> {
let record_used = record_used_id.is_some(); let record_used = record_used_id.is_some();
assert!(ns == TypeNS || ns == ValueNS);
if ns == TypeNS { if ns == TypeNS {
ident.span = if ident.name == keywords::SelfType.name() { ident.span = if ident.name == keywords::SelfType.name() {
// FIXME(jseyfried) improve `Self` hygiene // FIXME(jseyfried) improve `Self` hygiene
@ -1922,8 +1920,9 @@ impl<'a> Resolver<'a> {
return Some(LexicalScopeBinding::Item(binding)) return Some(LexicalScopeBinding::Item(binding))
} }
_ if poisoned.is_some() => break, _ if poisoned.is_some() => break,
Err(Undetermined) => return None, Err(Determined) => continue,
Err(Determined) => {} 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); ident.span, Mark::root()).to_name_binding(self.arenas);
return Some(LexicalScopeBinding::Item(binding)); 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 Some(prelude) = self.prelude {
if let Ok(binding) = self.resolve_ident_in_module_unadjusted(prelude, ident, ns, if let Ok(binding) = self.resolve_ident_in_module_unadjusted(prelude, ident, ns,
false, false, path_span) { false, false, path_span) {
@ -3505,6 +3509,8 @@ impl<'a> Resolver<'a> {
let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(def); let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(def);
if let Some(next_module) = binding.module() { if let Some(next_module) = binding.module() {
module = Some(next_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 { } else if def == Def::Err {
return PathResult::NonModule(err_path_resolution()); return PathResult::NonModule(err_path_resolution());
} else if opt_ns.is_some() && (is_last || maybe_assoc) { } else if opt_ns.is_some() && (is_last || maybe_assoc) {

View File

@ -8,9 +8,9 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use {AmbiguityError, CrateLint, Resolver, ResolutionError, resolve_error}; use {AmbiguityError, CrateLint, Resolver, ResolutionError, is_known_tool, resolve_error};
use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult}; use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, ToNameBinding};
use Namespace::{self, MacroNS}; use Namespace::{self, TypeNS, MacroNS};
use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport}; use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
use resolve_imports::ImportResolver; use resolve_imports::ImportResolver;
use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex, 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::hygiene::{self, Mark};
use syntax::ext::placeholders::placeholder; use syntax::ext::placeholders::placeholder;
use syntax::ext::tt::macro_rules; 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::fold::{self, Folder};
use syntax::parse::parser::PathStyle; use syntax::parse::parser::PathStyle;
use syntax::parse::token::{self, Token}; use syntax::parse::token::{self, Token};
@ -326,6 +326,18 @@ impl<'a> base::Resolver for Resolver<'a> {
if let Def::Macro(_, MacroKind::ProcMacroStub) = def { if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
self.report_proc_macro_stub(invoc.span()); self.report_proc_macro_stub(invoc.span());
return Err(Determinacy::Determined); 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(); let def_id = def.def_id();
@ -348,6 +360,9 @@ impl<'a> base::Resolver for Resolver<'a> {
if let Def::Macro(_, MacroKind::ProcMacroStub) = def { if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
self.report_proc_macro_stub(path.span); self.report_proc_macro_stub(path.span);
return Err(Determinacy::Determined); 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()); self.unused_macros.remove(&def.def_id());
Ok(self.get_macro(def)) 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"); "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) fn resolve_invoc_to_def(&mut self, invoc: &mut Invocation, scope: Mark, force: bool)
-> Result<Def, Determinacy> { -> Result<Def, Determinacy> {
let (attr, traits, item) = match invoc.kind { 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) fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
-> Result<Def, Determinacy> { -> 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 { if !self.session.features_untracked().proc_macro_path_invoc {
emit_feature_err( emit_feature_err(
&self.session.parse_sess, &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 def
} }
@ -544,67 +563,226 @@ impl<'a> Resolver<'a> {
result 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, pub fn resolve_lexical_macro_path_segment(&mut self,
mut ident: Ident, mut ident: Ident,
ns: Namespace, ns: Namespace,
record_used: bool, record_used: bool,
path_span: Span) path_span: Span)
-> Result<MacroBinding<'a>, Determinacy> { -> Result<MacroBinding<'a>, Determinacy> {
ident = ident.modern(); // General principles:
let mut module = Some(self.current_module); // 1. Not controlled (user-defined) names should have higher priority than controlled names
let mut potential_illegal_shadower = Err(Determinacy::Determined); // built into the language or standard library. This way we can add new names into the
let determinacy = // language or standard library without breaking user code.
if record_used { Determinacy::Determined } else { Determinacy::Undetermined }; // 2. "Closed set" below means new names can appear after the current resolution attempt.
loop { // Places to search (in order of decreasing priority):
let orig_current_module = self.current_module; // (Type NS)
let result = if let Some(module) = module { // 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet
self.current_module = module; // Lexical resolutions can never be a privacy error. // (open set, not controlled).
// Since expanded macros may not shadow the lexical scope and // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
// globs may not shadow global macros (both enforced below), // (open, not controlled).
// we resolve with restricted shadowing (indicated by the penultimate argument). // 3. Extern prelude (closed, not controlled).
self.resolve_ident_in_module_unadjusted( // 4. Tool modules (closed, controlled right now, but not in the future).
module, ident, ns, true, record_used, path_span, // 5. Standard library prelude (de-facto closed, controlled).
).map(MacroBinding::Modern) // 6. Language prelude (closed, controlled).
} else { // (Macro NS)
self.macro_prelude.get(&ident.name).cloned().ok_or(determinacy) // 1. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
.map(MacroBinding::Global) // (open, not controlled).
}; // 2. Macro prelude (language, standard library, user-defined legacy plugins lumped into
self.current_module = orig_current_module; // 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) { assert!(ns == TypeNS || ns == MacroNS);
Ok(binding) => { ident = ident.modern();
if !record_used {
return result; // 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,
}
// 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),
} }
if let Ok(MacroBinding::Modern(shadower)) = potential_illegal_shadower { }
if shadower.def() != binding.def() { WhereToResolve::BuiltinAttrs => {
let name = ident.name; 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 { self.ambiguity_errors.push(AmbiguityError {
span: path_span, span: path_span,
name, name: ident.name,
b1: shadower, b1: previous_result.binding(),
b2: binding, b2: binding,
lexical: true, 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 { // Found a solution that's not an ambiguity yet, but is "suspicious" and
Some(module) => self.hygienic_lexical_parent(module, &mut ident.span), // can participate in ambiguities later on.
None => return potential_illegal_shadower, // 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, pub fn resolve_legacy_scope(&mut self,

View File

@ -811,6 +811,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
HirDef::Label(..) | HirDef::Label(..) |
HirDef::Macro(..) | HirDef::Macro(..) |
HirDef::GlobalAsm(..) | HirDef::GlobalAsm(..) |
HirDef::ToolMod |
HirDef::NonMacroAttr |
HirDef::Err => None, HirDef::Err => None,
} }
} }

View File

@ -89,17 +89,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 { 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 { impl NestedMetaItem {
@ -245,10 +236,6 @@ impl Attribute {
pub fn is_value_str(&self) -> bool { pub fn is_value_str(&self) -> bool {
self.value_str().is_some() self.value_str().is_some()
} }
pub fn is_scoped(&self) -> bool {
self.path.segments.len() > 1
}
} }
impl MetaItem { impl MetaItem {

View File

@ -588,6 +588,9 @@ impl MacroKind {
/// An enum representing the different kinds of syntax extensions. /// An enum representing the different kinds of syntax extensions.
pub enum SyntaxExtension { 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 /// A syntax extension that is attached to an item and creates new items
/// based upon it. /// based upon it.
/// ///
@ -667,6 +670,7 @@ impl SyntaxExtension {
SyntaxExtension::IdentTT(..) | SyntaxExtension::IdentTT(..) |
SyntaxExtension::ProcMacro { .. } => SyntaxExtension::ProcMacro { .. } =>
MacroKind::Bang, MacroKind::Bang,
SyntaxExtension::NonMacroAttr |
SyntaxExtension::MultiDecorator(..) | SyntaxExtension::MultiDecorator(..) |
SyntaxExtension::MultiModifier(..) | SyntaxExtension::MultiModifier(..) |
SyntaxExtension::AttrProcMacro(..) => SyntaxExtension::AttrProcMacro(..) =>
@ -696,6 +700,7 @@ impl SyntaxExtension {
SyntaxExtension::AttrProcMacro(.., edition) | SyntaxExtension::AttrProcMacro(.., edition) |
SyntaxExtension::ProcMacroDerive(.., edition) => edition, SyntaxExtension::ProcMacroDerive(.., edition) => edition,
// Unstable legacy stuff // Unstable legacy stuff
SyntaxExtension::NonMacroAttr |
SyntaxExtension::IdentTT(..) | SyntaxExtension::IdentTT(..) |
SyntaxExtension::MultiDecorator(..) | SyntaxExtension::MultiDecorator(..) |
SyntaxExtension::MultiModifier(..) | SyntaxExtension::MultiModifier(..) |

View File

@ -36,7 +36,7 @@ use visit::{self, Visitor};
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
use std::mem; use std::{iter, mem};
use std::rc::Rc; use std::rc::Rc;
use std::path::PathBuf; use std::path::PathBuf;
@ -243,6 +243,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> { pub fn attr_id(&self) -> Option<ast::AttrId> {
match self.kind { match self.kind {
InvocationKind::Attr { attr: Some(ref attr), .. } => Some(attr.id), InvocationKind::Attr { attr: Some(ref attr), .. } => Some(attr.id),
@ -566,6 +575,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}); });
match *ext { 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) => { MultiModifier(ref mac) => {
let meta = attr.parse_meta(self.cx.parse_sess) let meta = attr.parse_meta(self.cx.parse_sess)
.map_err(|mut e| { e.emit(); }).ok()?; .map_err(|mut e| { e.emit(); }).ok()?;
@ -810,7 +824,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
} }
} }
MultiDecorator(..) | MultiModifier(..) | AttrProcMacro(..) => { MultiDecorator(..) | MultiModifier(..) |
AttrProcMacro(..) | SyntaxExtension::NonMacroAttr => {
self.cx.span_err(path.span, self.cx.span_err(path.span,
&format!("`{}` can only be used in attributes", path)); &format!("`{}` can only be used in attributes", path));
self.cx.trace_macros_diag(); self.cx.trace_macros_diag();
@ -1612,13 +1627,16 @@ impl<'feat> ExpansionConfig<'feat> {
fn enable_allow_internal_unstable = allow_internal_unstable, fn enable_allow_internal_unstable = allow_internal_unstable,
fn enable_custom_derive = custom_derive, fn enable_custom_derive = custom_derive,
fn enable_format_args_nl = format_args_nl, 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 macros_in_extern_enabled = macros_in_extern,
fn proc_macro_mod = proc_macro_mod, fn proc_macro_mod = proc_macro_mod,
fn proc_macro_gen = proc_macro_gen, fn proc_macro_gen = proc_macro_gen,
fn proc_macro_expr = proc_macro_expr, fn proc_macro_expr = proc_macro_expr,
fn proc_macro_non_items = proc_macro_non_items, 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. // A Marker adds the given mark to the syntax context.

View File

@ -80,6 +80,11 @@ macro_rules! declare_features {
{ {
$(f(stringify!($feature), self.$feature);)+ $(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() 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 { pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name)) || BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name)) ||
attr.name().as_str().starts_with("rustc_") attr.name().as_str().starts_with("rustc_")
@ -1198,28 +1207,9 @@ impl<'a> Context<'a> {
// before the plugin attributes are registered // before the plugin attributes are registered
// so we skip this then // so we skip this then
if !is_macro { if !is_macro {
if attr.is_scoped() { let msg = format!("The attribute `{}` is currently unknown to the compiler and \
gate_feature!(self, tool_attributes, attr.span, may have meaning added to it in the future", attr.path);
&format!("scoped attribute `{}` is experimental", attr.path)); gate_feature!(self, custom_attribute, attr.span, &msg);
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));
}
} }
} }
} }
@ -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 return
} }
@ -2004,7 +1994,7 @@ impl FeatureChecker {
// the branching can be eliminated by modifying `set!()` to set these spans // the branching can be eliminated by modifying `set!()` to set these spans
// only for the features that need to be checked for mutual exclusion. // only for the features that need to be checked for mutual exclusion.
fn collect(&mut self, features: &Features, span: Span) { 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) // If self.use_extern_macros is None, set to Some(span)
self.use_extern_macros = self.use_extern_macros.or(Some(span)); self.use_extern_macros = self.use_extern_macros.or(Some(span));
} }

View File

@ -8,9 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // 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 failed to resolve. Use of undeclared type or module `foo`
#[foo::bar] //~ ERROR an unknown tool name found in scoped attribute: `foo::bar`. [E0694]
fn main() {} fn main() {}

View File

@ -11,7 +11,7 @@
// aux-build:issue-42708.rs // aux-build:issue-42708.rs
// ignore-stage1 // ignore-stage1
#![feature(decl_macro, use_extern_macros, proc_macro_path_invoc)] #![feature(decl_macro, proc_macro_path_invoc)]
#![allow(unused)] #![allow(unused)]
extern crate issue_42708; extern crate issue_42708;

View File

@ -11,7 +11,7 @@
// aux-build:issue-50061.rs // aux-build:issue-50061.rs
// ignore-stage1 // ignore-stage1
#![feature(use_extern_macros, proc_macro_path_invoc, decl_macro)] #![feature(proc_macro_path_invoc, decl_macro)]
extern crate issue_50061; extern crate issue_50061;

View File

@ -11,7 +11,7 @@
// aux-build:parent-source-spans.rs // aux-build:parent-source-spans.rs
// ignore-stage1 // ignore-stage1
#![feature(use_extern_macros, decl_macro, proc_macro_non_items)] #![feature(decl_macro, proc_macro_non_items)]
extern crate parent_source_spans; extern crate parent_source_spans;

View File

@ -12,3 +12,8 @@
macro_rules! mac { macro_rules! mac {
($ident:ident) => { let $ident = 42; } ($ident:ident) => { let $ident = 42; }
} }
#[macro_export]
macro_rules! inline {
() => ()
}

View File

@ -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 --> $DIR/feature-gate-macros_in_extern.rs:29:5
| |
LL | returns_isize!(rust_get_test_int); 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 = 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 --> $DIR/feature-gate-macros_in_extern.rs:31:5
| |
LL | takes_u32_returns_u32!(rust_dbg_extern_identity_u32); 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 = 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 --> $DIR/feature-gate-macros_in_extern.rs:33:5
| |
LL | emits_nothing!(); LL | emits_nothing!();

View File

@ -8,8 +8,10 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#![feature(use_extern_macros)]
fn main() { fn main() {
#[rustfmt::skip] //~ ERROR scoped attribute `rustfmt::skip` is experimental #[rustfmt::skip] //~ ERROR tool attributes are unstable
let x = 3 let x = 3
; ;
} }

View File

@ -1,7 +1,7 @@
error[E0658]: scoped attribute `rustfmt::skip` is experimental (see issue #44690) error[E0658]: tool attributes are unstable (see issue #44690)
--> $DIR/feature-gate-tool_attributes.rs:12:5 --> $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 = help: add #![feature(tool_attributes)] to the crate attributes to enable

View File

@ -9,6 +9,6 @@
// except according to those terms. // except according to those terms.
fn main() { fn main() {
print!(test!()); print!(testo!());
//~^ ERROR: format argument must be a string literal //~^ ERROR: format argument must be a string literal
} }

View File

@ -1,11 +1,11 @@
error: format argument must be a string literal error: format argument must be a string literal
--> $DIR/issue-11692-1.rs:12:12 --> $DIR/issue-11692-1.rs:12:12
| |
LL | print!(test!()); LL | print!(testo!());
| ^^^^^^^ | ^^^^^^^^
help: you might be missing a string literal to format with help: you might be missing a string literal to format with
| |
LL | print!("{}", test!()); LL | print!("{}", testo!());
| ^^^^^ | ^^^^^
error: aborting due to previous error error: aborting due to previous error

View File

@ -10,5 +10,5 @@
fn main() { fn main() {
concat!(test!()); concat!(test!());
//~^ ERROR cannot find macro `test!` in this scope //~^ ERROR expected a macro, found non-macro attribute
} }

View File

@ -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 --> $DIR/issue-11692-2.rs:12:13
| |
LL | concat!(test!()); LL | concat!(test!());

View File

@ -10,7 +10,7 @@
// compile-pass // compile-pass
#![feature(use_extern_macros, decl_macro)] #![feature(decl_macro)]
mod type_ns { mod type_ns {
pub type A = u8; pub type A = u8;

View File

@ -8,11 +8,13 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // 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() {} fn main() {}

View File

@ -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`.

View File

@ -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() {}

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -8,8 +8,14 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
fn main() { // compile-pass
#[rustfmt::skip] //~ ERROR scoped attribute `rustfmt::skip` is experimental
let x = #![feature(use_extern_macros, extern_prelude)]
3;
mod m {
fn check() {
std::panic!(); // OK
}
} }
fn main() {}

View File

@ -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() {}

View File

@ -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`.

View File

@ -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() {}

View File

@ -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`.

View File

@ -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() {}

View File

@ -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`
}

View File

@ -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`.

View File

@ -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
}

View File

@ -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

View File

@ -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() {}

View File

@ -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`.