diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 1c355e35fd6..cb5e1e600d3 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -49,6 +49,7 @@ pub enum Def { PrimTy(hir::PrimTy), TyParam(DefId), SelfTy(Option /* trait */, Option /* 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", } } diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 410d578d404..cac0d182d3a 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -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 }); diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 4553a2ab577..ab4d15d0b90 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -629,7 +629,8 @@ impl<'a> Resolver<'a> { pub fn get_macro(&mut self, def: Def) -> Lrc { 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(); diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index ec067a6477b..4c12591c832 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -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, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index ca42cf6dace..9c58d2c1f0b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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,15 +204,10 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver, err.span_label(typaram_span, "type variable from outer function"); } }, - Def::Mod(..) | Def::Struct(..) | Def::Union(..) | Def::Enum(..) | Def::Variant(..) | - Def::Trait(..) | Def::TyAlias(..) | Def::TyForeign(..) | Def::TraitAlias(..) | - Def::AssociatedTy(..) | Def::PrimTy(..) | Def::Fn(..) | Def::Const(..) | - Def::Static(..) | Def::StructCtor(..) | Def::VariantCtor(..) | Def::Method(..) | - Def::AssociatedConst(..) | Def::Local(..) | Def::Upvar(..) | Def::Label(..) | - Def::Existential(..) | Def::AssociatedExistential(..) | - Def::Macro(..) | Def::GlobalAsm(..) | Def::Err => + _ => { bug!("TypeParametersFromOuterFunction should only be used with Def::SelfTy or \ Def::TyParam") + } } // Try to retrieve the span of the function signature and generate a new message with @@ -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> { 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) { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 1d42ad4e490..60a6bcf499d 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -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 { 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 { - 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, 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 = 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() { - let name = ident.name; + } + 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, diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 761521c8807..240b33c3c94 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -811,6 +811,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { HirDef::Label(..) | HirDef::Macro(..) | HirDef::GlobalAsm(..) | + HirDef::ToolMod | + HirDef::NonMacroAttr | HirDef::Err => None, } } diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 137b94230a3..938fd2767c9 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -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 { - RUST_KNOWN_LINT_TOOL.contains(&m_item.as_str().as_ref()) + ["clippy"].contains(&m_item.as_str().as_ref()) } impl NestedMetaItem { @@ -245,10 +236,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 { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index b55c4f99206..8450daa3f7c 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -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(..) | diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 9f8909e1626..1fd77045a45 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -36,7 +36,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; @@ -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 { match self.kind { InvocationKind::Attr { attr: Some(ref attr), .. } => Some(attr.id), @@ -566,6 +575,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()?; @@ -810,7 +824,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(); @@ -1612,13 +1627,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. diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 40fb2c69e57..747cf3f1654 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -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)); } diff --git a/src/test/compile-fail/unknown-tool-name.rs b/src/test/compile-fail/unknown-tool-name.rs index c2192a21d90..c4d22e6d392 100644 --- a/src/test/compile-fail/unknown-tool-name.rs +++ b/src/test/compile-fail/unknown-tool-name.rs @@ -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() {} diff --git a/src/test/run-pass-fulldeps/proc-macro/issue-42708.rs b/src/test/run-pass-fulldeps/proc-macro/issue-42708.rs index df4a1d8994b..d4af99f97c5 100644 --- a/src/test/run-pass-fulldeps/proc-macro/issue-42708.rs +++ b/src/test/run-pass-fulldeps/proc-macro/issue-42708.rs @@ -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; diff --git a/src/test/run-pass-fulldeps/proc-macro/issue-50061.rs b/src/test/run-pass-fulldeps/proc-macro/issue-50061.rs index 15dff94c88c..53783e7fedb 100644 --- a/src/test/run-pass-fulldeps/proc-macro/issue-50061.rs +++ b/src/test/run-pass-fulldeps/proc-macro/issue-50061.rs @@ -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; diff --git a/src/test/ui-fulldeps/proc-macro/parent-source-spans.rs b/src/test/ui-fulldeps/proc-macro/parent-source-spans.rs index a60841d848c..18f5b0f506c 100644 --- a/src/test/ui-fulldeps/proc-macro/parent-source-spans.rs +++ b/src/test/ui-fulldeps/proc-macro/parent-source-spans.rs @@ -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; diff --git a/src/test/ui/auxiliary/macro-in-other-crate.rs b/src/test/ui/auxiliary/macro-in-other-crate.rs index 01282f2ad24..c787cedc2d0 100644 --- a/src/test/ui/auxiliary/macro-in-other-crate.rs +++ b/src/test/ui/auxiliary/macro-in-other-crate.rs @@ -12,3 +12,8 @@ macro_rules! mac { ($ident:ident) => { let $ident = 42; } } + +#[macro_export] +macro_rules! inline { + () => () +} diff --git a/src/test/ui/feature-gate-macros_in_extern.stderr b/src/test/ui/feature-gate-macros_in_extern.stderr index 748adc390d8..5d7e01fbbb7 100644 --- a/src/test/ui/feature-gate-macros_in_extern.stderr +++ b/src/test/ui/feature-gate-macros_in_extern.stderr @@ -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!(); diff --git a/src/test/ui/feature-gate-tool_attributes.rs b/src/test/ui/feature-gate-tool_attributes.rs index 2b7cf56d938..47c623574ec 100644 --- a/src/test/ui/feature-gate-tool_attributes.rs +++ b/src/test/ui/feature-gate-tool_attributes.rs @@ -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 ; } diff --git a/src/test/ui/feature-gate-tool_attributes.stderr b/src/test/ui/feature-gate-tool_attributes.stderr index da89c4a5ef6..ebc266e004e 100644 --- a/src/test/ui/feature-gate-tool_attributes.stderr +++ b/src/test/ui/feature-gate-tool_attributes.stderr @@ -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 diff --git a/src/test/ui/issue-11692-1.rs b/src/test/ui/issue-11692-1.rs index f577aad04e6..ff6009da72f 100644 --- a/src/test/ui/issue-11692-1.rs +++ b/src/test/ui/issue-11692-1.rs @@ -9,6 +9,6 @@ // except according to those terms. fn main() { - print!(test!()); + print!(testo!()); //~^ ERROR: format argument must be a string literal } diff --git a/src/test/ui/issue-11692-1.stderr b/src/test/ui/issue-11692-1.stderr index bee73e9f568..61ff455d16c 100644 --- a/src/test/ui/issue-11692-1.stderr +++ b/src/test/ui/issue-11692-1.stderr @@ -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 diff --git a/src/test/ui/issue-11692-2.rs b/src/test/ui/issue-11692-2.rs index acac2d151fe..c595b0fb2c2 100644 --- a/src/test/ui/issue-11692-2.rs +++ b/src/test/ui/issue-11692-2.rs @@ -10,5 +10,5 @@ fn main() { concat!(test!()); - //~^ ERROR cannot find macro `test!` in this scope + //~^ ERROR expected a macro, found non-macro attribute } diff --git a/src/test/ui/issue-11692-2.stderr b/src/test/ui/issue-11692-2.stderr index 51d6041e922..3d080bd46dc 100644 --- a/src/test/ui/issue-11692-2.stderr +++ b/src/test/ui/issue-11692-2.stderr @@ -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!()); diff --git a/src/test/ui/issue-50187.rs b/src/test/ui/issue-50187.rs index 87acf106393..ccb2742841c 100644 --- a/src/test/ui/issue-50187.rs +++ b/src/test/ui/issue-50187.rs @@ -10,7 +10,7 @@ // compile-pass -#![feature(use_extern_macros, decl_macro)] +#![feature(decl_macro)] mod type_ns { pub type A = u8; diff --git a/src/test/compile-fail/unknown_tool_attributes-1.rs b/src/test/ui/macro-path-prelude-fail-1.rs similarity index 62% rename from src/test/compile-fail/unknown_tool_attributes-1.rs rename to src/test/ui/macro-path-prelude-fail-1.rs index ba38c297a11..b953805a7eb 100644 --- a/src/test/compile-fail/unknown_tool_attributes-1.rs +++ b/src/test/ui/macro-path-prelude-fail-1.rs @@ -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() {} diff --git a/src/test/ui/macro-path-prelude-fail-1.stderr b/src/test/ui/macro-path-prelude-fail-1.stderr new file mode 100644 index 00000000000..fc74937d912 --- /dev/null +++ b/src/test/ui/macro-path-prelude-fail-1.stderr @@ -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`. diff --git a/src/test/ui/macro-path-prelude-fail-2.rs b/src/test/ui/macro-path-prelude-fail-2.rs new file mode 100644 index 00000000000..ec77e276bd4 --- /dev/null +++ b/src/test/ui/macro-path-prelude-fail-2.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/test/ui/macro-path-prelude-fail-2.stderr b/src/test/ui/macro-path-prelude-fail-2.stderr new file mode 100644 index 00000000000..d23aed847a3 --- /dev/null +++ b/src/test/ui/macro-path-prelude-fail-2.stderr @@ -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 + diff --git a/src/test/ui/macro-path-prelude-fail-3.rs b/src/test/ui/macro-path-prelude-fail-3.rs new file mode 100644 index 00000000000..4cf90019d40 --- /dev/null +++ b/src/test/ui/macro-path-prelude-fail-3.rs @@ -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 or the MIT license +// , 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 +} diff --git a/src/test/ui/macro-path-prelude-fail-3.stderr b/src/test/ui/macro-path-prelude-fail-3.stderr new file mode 100644 index 00000000000..bd1015b7ee1 --- /dev/null +++ b/src/test/ui/macro-path-prelude-fail-3.stderr @@ -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 + diff --git a/src/test/compile-fail/feature-gate-tool_attributes.rs b/src/test/ui/macro-path-prelude-pass.rs similarity index 77% rename from src/test/compile-fail/feature-gate-tool_attributes.rs rename to src/test/ui/macro-path-prelude-pass.rs index 5a7536ca330..bc58754513b 100644 --- a/src/test/compile-fail/feature-gate-tool_attributes.rs +++ b/src/test/ui/macro-path-prelude-pass.rs @@ -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() {} diff --git a/src/test/ui/macro-path-prelude-shadowing.rs b/src/test/ui/macro-path-prelude-shadowing.rs new file mode 100644 index 00000000000..1aff7777ef7 --- /dev/null +++ b/src/test/ui/macro-path-prelude-shadowing.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/test/ui/macro-path-prelude-shadowing.stderr b/src/test/ui/macro-path-prelude-shadowing.stderr new file mode 100644 index 00000000000..0e1b9a985a3 --- /dev/null +++ b/src/test/ui/macro-path-prelude-shadowing.stderr @@ -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`. diff --git a/src/test/ui/tool-attributes-disabled-1.rs b/src/test/ui/tool-attributes-disabled-1.rs new file mode 100644 index 00000000000..87d47b75607 --- /dev/null +++ b/src/test/ui/tool-attributes-disabled-1.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/test/ui/tool-attributes-disabled-1.stderr b/src/test/ui/tool-attributes-disabled-1.stderr new file mode 100644 index 00000000000..6302c06057a --- /dev/null +++ b/src/test/ui/tool-attributes-disabled-1.stderr @@ -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`. diff --git a/src/test/ui/tool-attributes-disabled-2.rs b/src/test/ui/tool-attributes-disabled-2.rs new file mode 100644 index 00000000000..160dda05b1e --- /dev/null +++ b/src/test/ui/tool-attributes-disabled-2.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/test/ui/tool-attributes-misplaced-1.rs b/src/test/ui/tool-attributes-misplaced-1.rs new file mode 100644 index 00000000000..b3355352423 --- /dev/null +++ b/src/test/ui/tool-attributes-misplaced-1.rs @@ -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 or the MIT license +// , 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` +} diff --git a/src/test/ui/tool-attributes-misplaced-1.stderr b/src/test/ui/tool-attributes-misplaced-1.stderr new file mode 100644 index 00000000000..b9e61121406 --- /dev/null +++ b/src/test/ui/tool-attributes-misplaced-1.stderr @@ -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`. diff --git a/src/test/ui/tool-attributes-misplaced-2.rs b/src/test/ui/tool-attributes-misplaced-2.rs new file mode 100644 index 00000000000..3bb0e3dc343 --- /dev/null +++ b/src/test/ui/tool-attributes-misplaced-2.rs @@ -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 or the MIT license +// , 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 +} diff --git a/src/test/ui/tool-attributes-misplaced-2.stderr b/src/test/ui/tool-attributes-misplaced-2.stderr new file mode 100644 index 00000000000..66452267e94 --- /dev/null +++ b/src/test/ui/tool-attributes-misplaced-2.stderr @@ -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 + diff --git a/src/test/ui/tool-attributes-shadowing.rs b/src/test/ui/tool-attributes-shadowing.rs new file mode 100644 index 00000000000..7913c9f40b5 --- /dev/null +++ b/src/test/ui/tool-attributes-shadowing.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/test/ui/tool-attributes-shadowing.stderr b/src/test/ui/tool-attributes-shadowing.stderr new file mode 100644 index 00000000000..f668d677f7a --- /dev/null +++ b/src/test/ui/tool-attributes-shadowing.stderr @@ -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`.