From cdd934ea1dabd72e09bcda7a9954905df3c9ee47 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 28 Feb 2019 08:51:35 +0300 Subject: [PATCH 1/2] Do not accidentally treat multi-segment meta-items as single-segment --- src/librustc/hir/check_attr.rs | 8 +- src/librustc/ich/impls_syntax.rs | 5 +- src/librustc/lint/levels.rs | 21 ++-- src/librustc/middle/lib_features.rs | 6 +- src/librustc/middle/stability.rs | 11 +- src/librustc/session/config.rs | 3 +- src/librustc/traits/on_unimplemented.rs | 10 +- src/librustc_incremental/assert_dep_graph.rs | 6 +- .../persist/dirty_clean.rs | 2 +- src/librustc_lint/builtin.rs | 2 +- src/librustc_lint/unused.rs | 8 +- src/librustc_passes/layout_test.rs | 4 +- src/librustc_plugin/load.rs | 4 +- src/librustc_resolve/build_reduced_graph.rs | 23 ++-- src/librustdoc/clean/cfg.rs | 8 +- src/librustdoc/clean/mod.rs | 6 +- src/librustdoc/core.rs | 3 +- src/librustdoc/html/render.rs | 14 +-- src/librustdoc/visit_ast.rs | 7 +- src/libsyntax/attr/builtin.rs | 94 ++++++++------- src/libsyntax/attr/mod.rs | 77 ++++++------- src/libsyntax/ext/expand.rs | 4 +- src/libsyntax/ext/tt/macro_rules.rs | 11 +- src/libsyntax/feature_gate.rs | 33 +++--- src/libsyntax/test.rs | 5 +- src/libsyntax_ext/deriving/custom.rs | 8 +- src/libsyntax_ext/deriving/generic/mod.rs | 9 +- src/libsyntax_ext/proc_macro_decls.rs | 55 +++++---- src/test/ui/proc-macro/attribute.rs | 94 +++++++++------ src/test/ui/proc-macro/attribute.stderr | 108 ++++++++++++++---- src/test/ui/proc-macro/shadow-builtin.rs | 14 --- src/test/ui/proc-macro/shadow-builtin.stderr | 8 -- 32 files changed, 375 insertions(+), 296 deletions(-) delete mode 100644 src/test/ui/proc-macro/shadow-builtin.rs delete mode 100644 src/test/ui/proc-macro/shadow-builtin.stderr diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index ddc1eebe645ae..aebe17a8a7810 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -166,7 +166,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { // ``` let hints: Vec<_> = item.attrs .iter() - .filter(|attr| attr.name() == "repr") + .filter(|attr| attr.check_name("repr")) .filter_map(|attr| attr.meta_item_list()) .flatten() .collect(); @@ -177,7 +177,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { let mut is_transparent = false; for hint in &hints { - let name = if let Some(name) = hint.name() { + let name = if let Some(name) = hint.ident_str() { name } else { // Invalid repr hint like repr(42). We don't check for unrecognized hints here @@ -185,7 +185,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { continue; }; - let (article, allowed_targets) = match &*name.as_str() { + let (article, allowed_targets) = match name { "C" | "align" => { is_c |= name == "C"; if target != Target::Struct && @@ -313,7 +313,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { fn check_used(&self, item: &hir::Item, target: Target) { for attr in &item.attrs { - if attr.name() == "used" && target != Target::Static { + if attr.check_name("used") && target != Target::Static { self.tcx.sess .span_err(attr.span, "attribute must be applied to a `static` variable"); } diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index f34423ccca655..0a1dda7a9cffd 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -197,7 +197,8 @@ impl<'a> HashStable> for [ast::Attribute] { let filtered: SmallVec<[&ast::Attribute; 8]> = self .iter() .filter(|attr| { - !attr.is_sugared_doc && !hcx.is_ignored_attr(attr.name()) + !attr.is_sugared_doc && + !attr.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name)) }) .collect(); @@ -224,7 +225,7 @@ impl<'a> HashStable> for ast::Attribute { hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { // Make sure that these have been filtered out. - debug_assert!(!hcx.is_ignored_attr(self.name())); + debug_assert!(!self.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name))); debug_assert!(!self.is_sugared_doc); let ast::Attribute { diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index 924aa3fde0a08..2430e83122803 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -193,7 +193,7 @@ impl<'a> LintLevelsBuilder<'a> { struct_span_err!(sess, span, E0452, "malformed lint attribute") }; for attr in attrs { - let level = match Level::from_str(&attr.name().as_str()) { + let level = match attr.ident_str().and_then(|name| Level::from_str(name)) { None => continue, Some(lvl) => lvl, }; @@ -254,9 +254,9 @@ impl<'a> LintLevelsBuilder<'a> { } for li in metas { - let word = match li.word() { - Some(word) => word, - None => { + let meta_item = match li.meta_item() { + Some(meta_item) if meta_item.is_word() => meta_item, + _ => { let mut err = bad_attr(li.span); if let Some(item) = li.meta_item() { if let ast::MetaItemKind::NameValue(_) = item.node { @@ -269,23 +269,24 @@ impl<'a> LintLevelsBuilder<'a> { continue; } }; - let tool_name = if let Some(lint_tool) = word.is_scoped() { - if !attr::is_known_lint_tool(lint_tool) { + let tool_name = if meta_item.ident.segments.len() > 1 { + let tool_ident = meta_item.ident.segments[0].ident; + if !attr::is_known_lint_tool(tool_ident) { span_err!( sess, - lint_tool.span, + tool_ident.span, E0710, "an unknown tool name found in scoped lint: `{}`", - word.ident + meta_item.ident ); continue; } - Some(lint_tool.as_str()) + Some(tool_ident.as_str()) } else { None }; - let name = word.name(); + let name = meta_item.ident.segments.last().expect("empty lint name").ident.name; match store.check_lint_name(&name.as_str(), tool_name) { CheckLintNameResult::Ok(ids) => { let src = LintSource::Node(name, li.span, reason); diff --git a/src/librustc/middle/lib_features.rs b/src/librustc/middle/lib_features.rs index 331343e052dea..3e51f7e0094df 100644 --- a/src/librustc/middle/lib_features.rs +++ b/src/librustc/middle/lib_features.rs @@ -63,9 +63,9 @@ impl<'a, 'tcx> LibFeatureCollector<'a, 'tcx> { for meta in metas { if let Some(mi) = meta.meta_item() { // Find the `feature = ".."` meta-item. - match (&*mi.name().as_str(), mi.value_str()) { - ("feature", val) => feature = val, - ("since", val) => since = val, + match (mi.ident_str(), mi.value_str()) { + (Some("feature"), val) => feature = val, + (Some("since"), val) => since = val, _ => {} } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 707d3484982ed..1190103d849ec 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -197,11 +197,12 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { } else { // Emit errors for non-staged-api crates. for attr in attrs { - let tag = attr.name(); - if tag == "unstable" || tag == "stable" || tag == "rustc_deprecated" { - attr::mark_used(attr); - self.tcx.sess.span_err(attr.span(), "stability attributes may not be used \ - outside of the standard library"); + if let Some(tag) = attr.ident_str() { + if tag == "unstable" || tag == "stable" || tag == "rustc_deprecated" { + attr::mark_used(attr); + self.tcx.sess.span_err(attr.span, "stability attributes may not be used \ + outside of the standard library"); + } } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 65da458efbfff..9a18151d41b12 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1810,7 +1810,8 @@ pub fn parse_cfgspecs(cfgspecs: Vec) -> ast::CrateConfig { error!("argument value must be a string"); } MetaItemKind::NameValue(..) | MetaItemKind::Word => { - return (meta_item.name(), meta_item.value_str()); + let ident = meta_item.ident().expect("multi-segment cfg key"); + return (ident.name, meta_item.value_str()); } } } diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs index f61c32614cc93..e6d77f1537cd5 100644 --- a/src/librustc/traits/on_unimplemented.rs +++ b/src/librustc/traits/on_unimplemented.rs @@ -177,10 +177,12 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { for command in self.subcommands.iter().chain(Some(self)).rev() { if let Some(ref condition) = command.condition { if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| { - options.contains(&( - c.name().as_str().to_string(), - c.value_str().map(|s| s.as_str().to_string()) - )) + c.ident_str().map_or(false, |name| { + options.contains(&( + name.to_string(), + c.value_str().map(|s| s.as_str().to_string()) + )) + }) }) { debug!("evaluate: skipping {:?} due to condition", command); continue diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index fe44e0cbe6143..365de43fd7a26 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -99,9 +99,9 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { fn argument(&self, attr: &ast::Attribute) -> Option { let mut value = None; for list_item in attr.meta_item_list().unwrap_or_default() { - match list_item.word() { - Some(word) if value.is_none() => - value = Some(word.name()), + match list_item.ident() { + Some(ident) if list_item.is_word() && value.is_none() => + value = Some(ident.name), _ => // FIXME better-encapsulate meta_item (don't directly access `node`) span_bug!(list_item.span(), "unexpected meta-item {:?}", list_item.node), diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index c13a3533032a8..bd88d8cc57c69 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -576,7 +576,7 @@ fn expect_associated_value(tcx: TyCtxt<'_, '_, '_>, item: &NestedMetaItem) -> as if let Some(value) = item.value_str() { value } else { - let msg = if let Some(name) = item.name() { + let msg = if let Some(name) = item.ident_str() { format!("associated value expected for `{}`", name) } else { "expected an associated value".to_string() diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 40c9ef3f63cf5..cfd1e1c4e1858 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -757,7 +757,7 @@ impl LintPass for DeprecatedAttr { impl EarlyLintPass for DeprecatedAttr { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { for &&(n, _, _, ref g) in &self.depr_attrs { - if attr.name() == n { + if attr.ident_str() == Some(n) { if let &AttributeGate::Gated(Stability::Deprecated(link, suggestion), ref name, ref reason, diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 407e684293515..3fa7c43c9dd99 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -265,19 +265,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes { } } - let name = attr.name(); + let name = attr.ident_str(); if !attr::is_used(attr) { debug!("Emitting warning for: {:?}", attr); cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute"); // Is it a builtin attribute that must be used at the crate level? let known_crate = BUILTIN_ATTRIBUTES.iter() - .find(|&&(builtin, ty, ..)| name == builtin && ty == AttributeType::CrateLevel) + .find(|&&(builtin, ty, ..)| { + name == Some(builtin) && ty == AttributeType::CrateLevel + }) .is_some(); // Has a plugin registered this attribute as one that must be used at // the crate level? let plugin_crate = plugin_attributes.iter() - .find(|&&(ref x, t)| name == &**x && AttributeType::CrateLevel == t) + .find(|&&(ref x, t)| name == Some(x) && AttributeType::CrateLevel == t) .is_some(); if known_crate || plugin_crate { let msg = match attr.style { diff --git a/src/librustc_passes/layout_test.rs b/src/librustc_passes/layout_test.rs index d21707c578b2a..43dafef04abae 100644 --- a/src/librustc_passes/layout_test.rs +++ b/src/librustc_passes/layout_test.rs @@ -53,9 +53,7 @@ impl<'a, 'tcx> VarianceTest<'a, 'tcx> { // The `..` are the names of fields to dump. let meta_items = attr.meta_item_list().unwrap_or_default(); for meta_item in meta_items { - let name = meta_item.word().map(|mi| mi.name().as_str()); - let name = name.as_ref().map(|s| &s[..]).unwrap_or(""); - + let name = meta_item.ident_str().unwrap_or(""); match name { "abi" => { self.tcx diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index 1b88cf05f40d5..2f4332e71237d 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -56,10 +56,10 @@ pub fn load_plugins(sess: &Session, for plugin in plugins { // plugins must have a name and can't be key = value - match plugin.name() { + match plugin.ident_str() { Some(name) if !plugin.is_value_str() => { let args = plugin.meta_item_list().map(ToOwned::to_owned); - loader.load_plugin(plugin.span, &name.as_str(), args.unwrap_or_default()); + loader.load_plugin(plugin.span, name, args.unwrap_or_default()); }, _ => call_malformed_plugin_attribute(sess, attr.span), } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 29de5308a3cdb..174a921f0f398 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -466,10 +466,9 @@ impl<'a> Resolver<'a> { if let Some(attr) = attr::find_by_name(&item.attrs, "proc_macro_derive") { if let Some(trait_attr) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) { - if let Some(ident) = trait_attr.name().map(Ident::with_empty_ctxt) { - let sp = trait_attr.span; + if let Some(ident) = trait_attr.ident() { let def = Def::Macro(def.def_id(), MacroKind::ProcMacroStub); - self.define(parent, ident, MacroNS, (def, vis, sp, expansion)); + self.define(parent, ident, MacroNS, (def, vis, ident.span, expansion)); } } } @@ -815,9 +814,9 @@ impl<'a> Resolver<'a> { break; } MetaItemKind::List(nested_metas) => for nested_meta in nested_metas { - match nested_meta.word() { - Some(word) => single_imports.push((word.name(), word.span)), - None => ill_formed(nested_meta.span), + match nested_meta.ident() { + Some(ident) if nested_meta.is_word() => single_imports.push(ident), + _ => ill_formed(nested_meta.span), } } MetaItemKind::NameValue(..) => ill_formed(meta.span), @@ -853,23 +852,23 @@ impl<'a> Resolver<'a> { self.legacy_import_macro(ident.name, imported_binding, span, allow_shadowing); }); } else { - for (name, span) in single_imports.iter().cloned() { - let ident = Ident::with_empty_ctxt(name); + for ident in single_imports.iter().cloned() { let result = self.resolve_ident_in_module( ModuleOrUniformRoot::Module(module), ident, MacroNS, None, false, - span, + ident.span, ); if let Ok(binding) = result { - let directive = macro_use_directive(span); + let directive = macro_use_directive(ident.span); self.potentially_unused_imports.push(directive); let imported_binding = self.import(binding, directive); - self.legacy_import_macro(name, imported_binding, span, allow_shadowing); + self.legacy_import_macro(ident.name, imported_binding, + ident.span, allow_shadowing); } else { - span_err!(self.session, span, E0469, "imported macro not found"); + span_err!(self.session, ident.span, E0469, "imported macro not found"); } } } diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 45e1ea2d3a39d..7ebcf2cbd912c 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -58,7 +58,13 @@ impl Cfg { /// If the content is not properly formatted, it will return an error indicating what and where /// the error is. pub fn parse(cfg: &MetaItem) -> Result { - let name = cfg.name(); + let name = match cfg.ident() { + Some(ident) => ident.name, + None => return Err(InvalidCfgError { + msg: "expected a single identifier", + span: cfg.span + }), + }; match cfg.node { MetaItemKind::Word => Ok(Cfg::Cfg(name, None)), MetaItemKind::NameValue(ref lit) => match lit.node { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 03dff10877041..2dfe6b83f4076 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -491,7 +491,7 @@ impl Item { pub fn is_non_exhaustive(&self) -> bool { self.attrs.other_attrs.iter() - .any(|a| a.name().as_str() == "non_exhaustive") + .any(|a| a.check_name("non_exhaustive")) } /// Returns a documentation-level item type from the item. @@ -3665,7 +3665,7 @@ impl Clean> for doctree::ExternCrate { fn clean(&self, cx: &DocContext<'_, '_, '_>) -> Vec { let please_inline = self.vis.node.is_pub() && self.attrs.iter().any(|a| { - a.name() == "doc" && match a.meta_item_list() { + a.check_name("doc") && match a.meta_item_list() { Some(l) => attr::list_contains_name(&l, "inline"), None => false, } @@ -3704,7 +3704,7 @@ impl Clean> for doctree::Import { // #[doc(no_inline)] attribute is present. // Don't inline doc(hidden) imports so they can be stripped at a later stage. let mut denied = !self.vis.node.is_pub() || self.attrs.iter().any(|a| { - a.name() == "doc" && match a.meta_item_list() { + a.check_name("doc") && match a.meta_item_list() { Some(l) => attr::list_contains_name(&l, "no_inline") || attr::list_contains_name(&l, "hidden"), None => false, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 4f70751c90537..1c39735b72f95 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -567,8 +567,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt for attr in krate.module.as_ref().unwrap().attrs.lists("doc") { let diag = ctxt.sess().diagnostic(); - let name = attr.name().map(|s| s.as_str()); - let name = name.as_ref().map(|s| &s[..]); + let name = attr.ident_str(); if attr.is_word() { if name == Some("no_default_passes") { report_deprecated_attr("no_default_passes", diag); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index d711e4514a049..7f6a1df6ff928 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -562,8 +562,7 @@ pub fn run(mut krate: clean::Crate, // going to emit HTML if let Some(attrs) = krate.module.as_ref().map(|m| &m.attrs) { for attr in attrs.lists("doc") { - let name = attr.name().map(|s| s.as_str()); - match (name.as_ref().map(|s| &s[..]), attr.value_str()) { + match (attr.ident_str(), attr.value_str()) { (Some("html_favicon_url"), Some(s)) => { scx.layout.favicon = s.to_string(); } @@ -3718,19 +3717,19 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, } fn render_attribute(attr: &ast::MetaItem) -> Option { - let name = attr.name(); + let path = attr.ident.to_string(); if attr.is_word() { - Some(name.to_string()) + Some(path) } else if let Some(v) = attr.value_str() { - Some(format!("{} = {:?}", name, v.as_str())) + Some(format!("{} = {:?}", path, v.as_str())) } else if let Some(values) = attr.meta_item_list() { let display: Vec<_> = values.iter().filter_map(|attr| { attr.meta_item().and_then(|mi| render_attribute(mi)) }).collect(); if display.len() > 0 { - Some(format!("{}({})", name, display.join(", "))) + Some(format!("{}({})", path, display.join(", "))) } else { None } @@ -3754,8 +3753,7 @@ fn render_attributes(w: &mut fmt::Formatter<'_>, it: &clean::Item) -> fmt::Resul let mut attrs = String::new(); for attr in &it.attrs.other_attrs { - let name = attr.name(); - if !ATTRIBUTE_WHITELIST.contains(&&*name.as_str()) { + if !attr.ident_str().map_or(false, |name| ATTRIBUTE_WHITELIST.contains(&name)) { continue; } if let Some(s) = render_attribute(&attr.meta().unwrap()) { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 2428a823d0b39..e55d79239c844 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -178,9 +178,10 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { Some(kind) => { let name = if kind == MacroKind::Derive { item.attrs.lists("proc_macro_derive") - .filter_map(|mi| mi.name()) + .filter_map(|mi| mi.ident()) .next() .expect("proc-macro derives require a name") + .name } else { name }; @@ -193,8 +194,8 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> { if let Some(list) = mi.meta_item_list() { for inner_mi in list { - if let Some(name) = inner_mi.name() { - helpers.push(name); + if let Some(ident) = inner_mi.ident() { + helpers.push(ident.name); } } } diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index e84adc01cf04a..d97f817931077 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -1,6 +1,6 @@ //! Parsing and validation of builtin attributes -use crate::ast::{self, Attribute, MetaItem, Name, NestedMetaItemKind}; +use crate::ast::{self, Attribute, MetaItem, NestedMetaItemKind}; use crate::feature_gate::{Features, GatedCfg}; use crate::parse::ParseSess; @@ -10,8 +10,8 @@ use syntax_pos::{symbol::Symbol, Span}; use super::{list_contains_name, mark_used, MetaItemKind}; enum AttrError { - MultipleItem(Name), - UnknownMetaItem(Name, &'static [&'static str]), + MultipleItem(String), + UnknownMetaItem(String, &'static [&'static str]), MissingSince, MissingFeature, MultipleStabilityLevels, @@ -169,10 +169,7 @@ pub fn contains_feature_attr(attrs: &[Attribute], feature_name: &str) -> bool { attrs.iter().any(|item| { item.check_name("feature") && item.meta_item_list().map(|list| { - list.iter().any(|mi| { - mi.word().map(|w| w.name() == feature_name) - .unwrap_or(false) - }) + list.iter().any(|mi| mi.is_word() && mi.check_name(feature_name)) }).unwrap_or(false) }) } @@ -220,7 +217,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, let meta = meta.as_ref().unwrap(); let get = |meta: &MetaItem, item: &mut Option| { if item.is_some() { - handle_errors(sess, meta.span, AttrError::MultipleItem(meta.name())); + handle_errors(sess, meta.span, AttrError::MultipleItem(meta.ident.to_string())); return false } if let Some(v) = meta.value_str() { @@ -239,9 +236,9 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, )+ for meta in metas { if let Some(mi) = meta.meta_item() { - match &*mi.name().as_str() { + match mi.ident_str() { $( - stringify!($name) + Some(stringify!($name)) => if !get(mi, &mut $name) { continue 'outer }, )+ _ => { @@ -249,7 +246,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, handle_errors( sess, mi.span, - AttrError::UnknownMetaItem(mi.name(), expected), + AttrError::UnknownMetaItem(mi.ident.to_string(), expected), ); continue 'outer } @@ -269,7 +266,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, } } - match &*meta.name().as_str() { + match meta.ident_str().expect("not a stability level") { "rustc_deprecated" => { if rustc_depr.is_some() { span_err!(diagnostic, item_sp, E0540, @@ -323,16 +320,16 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, let mut issue = None; for meta in metas { if let Some(mi) = meta.meta_item() { - match &*mi.name().as_str() { - "feature" => if !get(mi, &mut feature) { continue 'outer }, - "reason" => if !get(mi, &mut reason) { continue 'outer }, - "issue" => if !get(mi, &mut issue) { continue 'outer }, + match mi.ident_str() { + Some("feature") => if !get(mi, &mut feature) { continue 'outer }, + Some("reason") => if !get(mi, &mut reason) { continue 'outer }, + Some("issue") => if !get(mi, &mut issue) { continue 'outer }, _ => { handle_errors( sess, meta.span, AttrError::UnknownMetaItem( - mi.name(), + mi.ident.to_string(), &["feature", "reason", "issue"] ), ); @@ -394,15 +391,17 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, for meta in metas { match &meta.node { NestedMetaItemKind::MetaItem(mi) => { - match &*mi.name().as_str() { - "feature" => if !get(mi, &mut feature) { continue 'outer }, - "since" => if !get(mi, &mut since) { continue 'outer }, + match mi.ident_str() { + Some("feature") => + if !get(mi, &mut feature) { continue 'outer }, + Some("since") => + if !get(mi, &mut since) { continue 'outer }, _ => { handle_errors( sess, meta.span, AttrError::UnknownMetaItem( - mi.name(), &["since", "note"], + mi.ident.to_string(), &["since", "note"], ), ); continue 'outer @@ -516,7 +515,8 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat true } MetaItemKind::NameValue(..) | MetaItemKind::Word => { - sess.config.contains(&(cfg.name(), cfg.value_str())) + let ident = cfg.ident().expect("multi-segment cfg predicate"); + sess.config.contains(&(ident.name, cfg.value_str())) } } }) @@ -546,14 +546,14 @@ pub fn eval_condition(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F) // The unwraps below may look dangerous, but we've already asserted // that they won't fail with the loop above. - match &*cfg.name().as_str() { - "any" => mis.iter().any(|mi| { + match cfg.ident_str() { + Some("any") => mis.iter().any(|mi| { eval_condition(mi.meta_item().unwrap(), sess, eval) }), - "all" => mis.iter().all(|mi| { + Some("all") => mis.iter().all(|mi| { eval_condition(mi.meta_item().unwrap(), sess, eval) }), - "not" => { + Some("not") => { if mis.len() != 1 { span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern"); return false; @@ -561,8 +561,9 @@ pub fn eval_condition(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F) !eval_condition(mis[0].meta_item().unwrap(), sess, eval) }, - p => { - span_err!(sess.span_diagnostic, cfg.span, E0537, "invalid predicate `{}`", p); + _ => { + span_err!(sess.span_diagnostic, cfg.span, E0537, + "invalid predicate `{}`", cfg.ident); false } } @@ -616,7 +617,9 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess, MetaItemKind::List(list) => { let get = |meta: &MetaItem, item: &mut Option| { if item.is_some() { - handle_errors(sess, meta.span, AttrError::MultipleItem(meta.name())); + handle_errors( + sess, meta.span, AttrError::MultipleItem(meta.ident.to_string()) + ); return false } if let Some(v) = meta.value_str() { @@ -646,14 +649,15 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess, for meta in list { match &meta.node { NestedMetaItemKind::MetaItem(mi) => { - match &*mi.name().as_str() { - "since" => if !get(mi, &mut since) { continue 'outer }, - "note" => if !get(mi, &mut note) { continue 'outer }, + match mi.ident_str() { + Some("since") => if !get(mi, &mut since) { continue 'outer }, + Some("note") => if !get(mi, &mut note) { continue 'outer }, _ => { handle_errors( sess, - meta.span, - AttrError::UnknownMetaItem(mi.name(), &["since", "note"]), + meta.span(), + AttrError::UnknownMetaItem(mi.ident.to_string(), + &["since", "note"]), ); continue 'outer } @@ -738,19 +742,13 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec { } let mut recognised = false; - if let Some(mi) = item.word() { - let word = &*mi.name().as_str(); - let hint = match word { - "C" => Some(ReprC), - "packed" => Some(ReprPacked(1)), - "simd" => Some(ReprSimd), - "transparent" => Some(ReprTransparent), - _ => match int_type_of_word(word) { - Some(ity) => Some(ReprInt(ity)), - None => { - None - } - } + if item.is_word() { + let hint = match item.ident_str() { + Some("C") => Some(ReprC), + Some("packed") => Some(ReprPacked(1)), + Some("simd") => Some(ReprSimd), + Some("transparent") => Some(ReprTransparent), + name => name.and_then(|name| int_type_of_word(name)).map(ReprInt), }; if let Some(h) = hint { @@ -796,7 +794,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec { } } else { if let Some(meta_item) = item.meta_item() { - if meta_item.name() == "align" { + if meta_item.check_name("align") { if let MetaItemKind::NameValue(ref value) = meta_item.node { recognised = true; let mut err = struct_span_err!(diagnostic, item.span, E0693, diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index b5fc850731404..857325681c660 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -90,10 +90,12 @@ impl NestedMetaItem { self.meta_item().map_or(false, |meta_item| meta_item.check_name(name)) } - /// Returns the name of the meta item, e.g., `foo` in `#[foo]`, - /// `#[foo="bar"]` and `#[foo(bar)]`, if self is a MetaItem - pub fn name(&self) -> Option { - self.meta_item().and_then(|meta_item| Some(meta_item.name())) + /// For a single-segment meta-item returns its name, otherwise returns `None`. + pub fn ident(&self) -> Option { + self.meta_item().and_then(|meta_item| meta_item.ident()) + } + pub fn ident_str(&self) -> Option<&str> { + self.ident().map(|name| name.as_str().get()) } /// Gets the string value if self is a MetaItem and the MetaItem is a @@ -108,25 +110,14 @@ impl NestedMetaItem { |meta_item| meta_item.meta_item_list().and_then( |meta_item_list| { if meta_item_list.len() == 1 { - let nested_item = &meta_item_list[0]; - if nested_item.is_literal() { - Some((meta_item.name(), nested_item.literal().unwrap())) - } else { - None + if let Some(ident) = meta_item.ident() { + if let Some(lit) = meta_item_list[0].literal() { + return Some((ident.name, lit)); + } } } - else { - None - }})) - } - - /// Returns a MetaItem if self is a MetaItem with Kind Word. - pub fn word(&self) -> Option<&MetaItem> { - self.meta_item().and_then(|meta_item| if meta_item.is_word() { - Some(meta_item) - } else { - None - }) + None + })) } /// Gets a list of inner meta items from a list MetaItem type. @@ -146,7 +137,7 @@ impl NestedMetaItem { /// Returns `true` if self is a MetaItem and the meta item is a word. pub fn is_word(&self) -> bool { - self.word().is_some() + self.meta_item().map_or(false, |meta_item| meta_item.is_word()) } /// Returns `true` if self is a MetaItem and the meta item is a ValueString. @@ -160,10 +151,6 @@ impl NestedMetaItem { } } -fn name_from_path(path: &Path) -> Name { - path.segments.last().expect("empty path in attribute").ident.name -} - impl Attribute { /// Returns `true` if the attribute's path matches the argument. If it matches, then the /// attribute is marked as used. @@ -177,10 +164,16 @@ impl Attribute { matches } - /// Returns the **last** segment of the name of this attribute. - /// e.g., `foo` for `#[foo]`, `skip` for `#[rustfmt::skip]`. - pub fn name(&self) -> Name { - name_from_path(&self.path) + /// For a single-segment attribute returns its name, otherwise returns `None`. + pub fn ident(&self) -> Option { + if self.path.segments.len() == 1 { + Some(self.path.segments[0].ident) + } else { + None + } + } + pub fn ident_str(&self) -> Option<&str> { + self.ident().map(|name| name.as_str().get()) } pub fn value_str(&self) -> Option { @@ -195,7 +188,7 @@ impl Attribute { } pub fn is_word(&self) -> bool { - self.path.segments.len() == 1 && self.tokens.is_empty() + self.tokens.is_empty() } pub fn span(&self) -> Span { @@ -213,8 +206,16 @@ impl Attribute { } impl MetaItem { - pub fn name(&self) -> Name { - name_from_path(&self.ident) + /// For a single-segment meta-item returns its name, otherwise returns `None`. + pub fn ident(&self) -> Option { + if self.ident.segments.len() == 1 { + Some(self.ident.segments[0].ident) + } else { + None + } + } + pub fn ident_str(&self) -> Option<&str> { + self.ident().map(|name| name.as_str().get()) } // #[attribute(name = "value")] @@ -255,7 +256,7 @@ impl MetaItem { pub fn span(&self) -> Span { self.span } pub fn check_name(&self, name: &str) -> bool { - self.name() == name + self.ident == name } pub fn is_value_str(&self) -> bool { @@ -265,14 +266,6 @@ impl MetaItem { pub fn is_meta_item_list(&self) -> bool { self.meta_item_list().is_some() } - - pub fn is_scoped(&self) -> Option { - if self.ident.segments.len() > 1 { - Some(self.ident.segments[0].ident) - } else { - None - } - } } impl Attribute { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index b805213bb1a4c..46342e162cf9b 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -601,7 +601,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { res } ProcMacroDerive(..) | BuiltinDerive(..) => { - self.cx.span_err(attr.span, &format!("`{}` is a derive mode", attr.path)); + self.cx.span_err(attr.span, &format!("`{}` is a derive macro", attr.path)); self.cx.trace_macros_diag(); invoc.fragment_kind.dummy(attr.span) } @@ -822,7 +822,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } ProcMacroDerive(..) | BuiltinDerive(..) => { - self.cx.span_err(path.span, &format!("`{}` is a derive mode", path)); + self.cx.span_err(path.span, &format!("`{}` is a derive macro", path)); self.cx.trace_macros_diag(); kind.dummy(span) } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index bd64bb010219b..12912044e4e3d 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -380,9 +380,14 @@ pub fn compile( .map(|attr| attr .meta_item_list() .map(|list| list.iter() - .map(|it| it.name().unwrap_or_else(|| sess.span_diagnostic.span_bug( - it.span, "allow internal unstable expects feature names", - ))) + .filter_map(|it| { + let name = it.ident().map(|ident| ident.name); + if name.is_none() { + sess.span_diagnostic.span_err(it.span(), + "allow internal unstable expects feature names") + } + name + }) .collect::>().into() ) .unwrap_or_else(|| { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index cc1953e69d4ca..805e450f32ea7 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1286,9 +1286,8 @@ pub struct GatedCfg { impl GatedCfg { pub fn gate(cfg: &ast::MetaItem) -> Option { - let name = cfg.name().as_str(); GATED_CFGS.iter() - .position(|info| info.0 == name) + .position(|info| cfg.check_name(info.0)) .map(|idx| { GatedCfg { span: cfg.span, @@ -1339,16 +1338,16 @@ macro_rules! gate_feature { impl<'a> Context<'a> { fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) { debug!("check_attribute(attr = {:?})", attr); - let name = attr.name().as_str(); + let name = attr.ident_str(); for &(n, ty, _template, ref gateage) in BUILTIN_ATTRIBUTES { - if name == n { + if name == Some(n) { if let Gated(_, name, desc, ref has_feature) = *gateage { if !attr.span.allows_unstable(name) { gate_feature_fn!( self, has_feature, attr.span, name, desc, GateStrength::Hard ); } - } else if name == "doc" { + } else if n == "doc" { if let Some(content) = attr.meta_item_list() { if content.iter().any(|c| c.check_name("include")) { gate_feature!(self, external_doc, attr.span, @@ -1371,7 +1370,7 @@ impl<'a> Context<'a> { } } if !attr::is_known(attr) { - if name.starts_with("rustc_") { + if name.map_or(false, |name| name.starts_with("rustc_")) { let msg = "unless otherwise specified, attributes with the prefix `rustc_` \ are reserved for internal compiler diagnostics"; gate_feature!(self, rustc_attrs, attr.span, msg); @@ -2043,13 +2042,12 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], }; for mi in list { - let name = if let Some(word) = mi.word() { - word.name() - } else { - continue + let name = match mi.ident_str() { + Some(name) if mi.is_word() => name, + _ => continue, }; - if incomplete_features.iter().any(|f| *f == name.as_str()) { + if incomplete_features.iter().any(|f| *f == name) { span_handler.struct_span_warn( mi.span, &format!( @@ -2089,12 +2087,13 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], }; for mi in list { - let name = if let Some(word) = mi.word() { - word.name() - } else { - span_err!(span_handler, mi.span, E0556, - "malformed feature, expected just one word"); - continue + let name = match mi.ident() { + Some(ident) if mi.is_word() => ident.name, + _ => { + span_err!(span_handler, mi.span, E0556, + "malformed feature, expected just one word"); + continue + } }; if let Some(edition) = edition_enabled_features.get(&name) { diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 56290fa771ba9..3afd55899c8f6 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -438,6 +438,9 @@ fn get_test_runner(sd: &errors::Handler, krate: &ast::Crate) -> Option meta_item.ident.clone(), + _ => sd.span_fatal(test_attr.span, "`test_runner` argument must be a path").raise() + } }) } diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs index cfc3c931598a1..e73110717e979 100644 --- a/src/libsyntax_ext/deriving/custom.rs +++ b/src/libsyntax_ext/deriving/custom.rs @@ -17,9 +17,11 @@ struct MarkAttrs<'a>(&'a [ast::Name]); impl<'a> Visitor<'a> for MarkAttrs<'a> { fn visit_attribute(&mut self, attr: &Attribute) { - if self.0.contains(&attr.name()) { - mark_used(attr); - mark_known(attr); + if let Some(ident) = attr.ident() { + if self.0.contains(&ident.name) { + mark_used(attr); + mark_known(attr); + } } } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index b8f96c5bc0ea9..2bb98c1bf625c 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -463,12 +463,9 @@ impl<'a> TraitDef<'a> { let mut attrs = newitem.attrs.clone(); attrs.extend(item.attrs .iter() - .filter(|a| { - match &*a.name().as_str() { - "allow" | "warn" | "deny" | "forbid" | "stable" | "unstable" => true, - _ => false, - } - }) + .filter(|a| a.ident_str().map_or(false, |name| { + ["allow", "warn", "deny", "forbid", "stable", "unstable"].contains(&name) + })) .cloned()); push(Annotatable::Item(P(ast::Item { attrs: attrs, ..(*newitem).clone() }))) } diff --git a/src/libsyntax_ext/proc_macro_decls.rs b/src/libsyntax_ext/proc_macro_decls.rs index d8f8decef39b1..efa6ce56648eb 100644 --- a/src/libsyntax_ext/proc_macro_decls.rs +++ b/src/libsyntax_ext/proc_macro_decls.rs @@ -113,48 +113,63 @@ impl<'a> CollectProcMacros<'a> { "attribute must have either one or two arguments"); return } - let trait_attr = &list[0]; - let attributes_attr = list.get(1); - let trait_name = match trait_attr.name() { - Some(name) => name, + let trait_attr = match list[0].meta_item() { + Some(meta_item) => meta_item, _ => { - self.handler.span_err(trait_attr.span(), "not a meta item"); + self.handler.span_err(list[0].span(), "not a meta item"); + return + } + }; + let trait_ident = match trait_attr.ident() { + Some(trait_ident) if trait_attr.is_word() => trait_ident, + _ => { + self.handler.span_err(trait_attr.span, "must only be one word"); return } }; - if !trait_attr.is_word() { - self.handler.span_err(trait_attr.span(), "must only be one word"); - } - if deriving::is_builtin_trait(trait_name) { + if trait_ident.is_path_segment_keyword() { self.handler.span_err(trait_attr.span(), - "cannot override a built-in #[derive] mode"); + &format!("`{}` cannot be a name of derive macro", trait_ident)); + } + if deriving::is_builtin_trait(trait_ident.name) { + self.handler.span_err(trait_attr.span, + "cannot override a built-in derive macro"); } + let attributes_attr = list.get(1); let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr { if !attr.check_name("attributes") { self.handler.span_err(attr.span(), "second argument must be `attributes`") } attr.meta_item_list().unwrap_or_else(|| { self.handler.span_err(attr.span(), - "attribute must be of form: \ - `attributes(foo, bar)`"); + "attribute must be of form: `attributes(foo, bar)`"); &[] }).into_iter().filter_map(|attr| { - let name = match attr.name() { - Some(name) => name, + let attr = match attr.meta_item() { + Some(meta_item) => meta_item, _ => { self.handler.span_err(attr.span(), "not a meta item"); return None; - }, + } }; - if !attr.is_word() { - self.handler.span_err(attr.span(), "must only be one word"); - return None; + let ident = match attr.ident() { + Some(ident) if attr.is_word() => ident, + _ => { + self.handler.span_err(attr.span, "must only be one word"); + return None; + } + }; + if ident.is_path_segment_keyword() { + self.handler.span_err( + attr.span(), + &format!("`{}` cannot be a name of derive helper attribute", ident), + ); } - Some(name) + Some(ident.name) }).collect() } else { Vec::new() @@ -163,7 +178,7 @@ impl<'a> CollectProcMacros<'a> { if self.in_root && item.vis.node.is_pub() { self.derives.push(ProcMacroDerive { span: item.span, - trait_name, + trait_name: trait_ident.name, function_name: item.ident, attrs: proc_attrs, }); diff --git a/src/test/ui/proc-macro/attribute.rs b/src/test/ui/proc-macro/attribute.rs index a0b982d75f519..ac7d0b4c2b6c9 100644 --- a/src/test/ui/proc-macro/attribute.rs +++ b/src/test/ui/proc-macro/attribute.rs @@ -4,53 +4,73 @@ #![crate_type = "proc-macro"] extern crate proc_macro; +use proc_macro::*; #[proc_macro_derive] //~^ ERROR: attribute must be of the form -pub fn foo1(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - input -} +pub fn foo1(input: TokenStream) -> TokenStream { input } -#[proc_macro_derive = "foo"] +#[proc_macro_derive = ""] //~^ ERROR: attribute must be of the form -pub fn foo2(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - input -} - -#[proc_macro_derive( - a = "b" -)] -//~^^ ERROR: must only be one word -pub fn foo3(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - input -} - -#[proc_macro_derive(b, c, d)] +pub fn foo2(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(d3, a, b)] +//~^ ERROR: attribute must have either one or two arguments +pub fn foo3(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(d4, attributes(a), b)] //~^ ERROR: attribute must have either one or two arguments -pub fn foo4(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - input -} +pub fn foo4(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive("a")] +//~^ ERROR: not a meta item +pub fn foo5(input: TokenStream) -> TokenStream { input } -#[proc_macro_derive(d(e))] +#[proc_macro_derive(d6 = "")] //~^ ERROR: must only be one word -pub fn foo5(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - input -} +pub fn foo6(input: TokenStream) -> TokenStream { input } -#[proc_macro_derive(f, attributes(g = "h"))] +#[proc_macro_derive(m::d7)] //~^ ERROR: must only be one word -pub fn foo6(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - input -} +pub fn foo7(input: TokenStream) -> TokenStream { input } -#[proc_macro_derive(i, attributes(j(k)))] +#[proc_macro_derive(d8(a))] //~^ ERROR: must only be one word -pub fn foo7(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - input -} +pub fn foo8(input: TokenStream) -> TokenStream { input } -#[proc_macro_derive(l, attributes(m), n)] -//~^ ERROR: attribute must have either one or two arguments -pub fn foo8(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - input -} +#[proc_macro_derive(self)] +//~^ ERROR: `self` cannot be a name of derive macro +pub fn foo9(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(PartialEq)] +//~^ ERROR: cannot override a built-in derive macro +pub fn foo10(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(d11, a)] +//~^ ERROR: second argument must be `attributes` +//~| ERROR: attribute must be of form: `attributes(foo, bar)` +pub fn foo11(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(d12, attributes)] +//~^ ERROR: attribute must be of form: `attributes(foo, bar)` +pub fn foo12(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(d13, attributes("a"))] +//~^ ERROR: not a meta item +pub fn foo13(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(d14, attributes(a = ""))] +//~^ ERROR: must only be one word +pub fn foo14(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(d15, attributes(m::a))] +//~^ ERROR: must only be one word +pub fn foo15(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(d16, attributes(a(b)))] +//~^ ERROR: must only be one word +pub fn foo16(input: TokenStream) -> TokenStream { input } + +#[proc_macro_derive(d17, attributes(self))] +//~^ ERROR: `self` cannot be a name of derive helper attribute +pub fn foo17(input: TokenStream) -> TokenStream { input } diff --git a/src/test/ui/proc-macro/attribute.stderr b/src/test/ui/proc-macro/attribute.stderr index 231eb1f106898..cc17d383569fc 100644 --- a/src/test/ui/proc-macro/attribute.stderr +++ b/src/test/ui/proc-macro/attribute.stderr @@ -1,50 +1,110 @@ -error: must only be one word - --> $DIR/attribute.rs:21:5 +error: attribute must have either one or two arguments + --> $DIR/attribute.rs:17:1 | -LL | a = "b" - | ^^^^^^^ +LL | #[proc_macro_derive(d3, a, b)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: attribute must have either one or two arguments - --> $DIR/attribute.rs:28:1 + --> $DIR/attribute.rs:21:1 + | +LL | #[proc_macro_derive(d4, attributes(a), b)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: not a meta item + --> $DIR/attribute.rs:25:21 + | +LL | #[proc_macro_derive("a")] + | ^^^ + +error: must only be one word + --> $DIR/attribute.rs:29:21 | -LL | #[proc_macro_derive(b, c, d)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[proc_macro_derive(d6 = "")] + | ^^^^^^^ error: must only be one word - --> $DIR/attribute.rs:34:21 + --> $DIR/attribute.rs:33:21 | -LL | #[proc_macro_derive(d(e))] +LL | #[proc_macro_derive(m::d7)] + | ^^^^^ + +error: must only be one word + --> $DIR/attribute.rs:37:21 + | +LL | #[proc_macro_derive(d8(a))] + | ^^^^^ + +error: `self` cannot be a name of derive macro + --> $DIR/attribute.rs:41:21 + | +LL | #[proc_macro_derive(self)] | ^^^^ +error: cannot override a built-in derive macro + --> $DIR/attribute.rs:45:21 + | +LL | #[proc_macro_derive(PartialEq)] + | ^^^^^^^^^ + +error: second argument must be `attributes` + --> $DIR/attribute.rs:49:26 + | +LL | #[proc_macro_derive(d11, a)] + | ^ + +error: attribute must be of form: `attributes(foo, bar)` + --> $DIR/attribute.rs:49:26 + | +LL | #[proc_macro_derive(d11, a)] + | ^ + +error: attribute must be of form: `attributes(foo, bar)` + --> $DIR/attribute.rs:54:26 + | +LL | #[proc_macro_derive(d12, attributes)] + | ^^^^^^^^^^ + +error: not a meta item + --> $DIR/attribute.rs:58:37 + | +LL | #[proc_macro_derive(d13, attributes("a"))] + | ^^^ + error: must only be one word - --> $DIR/attribute.rs:40:35 + --> $DIR/attribute.rs:62:37 | -LL | #[proc_macro_derive(f, attributes(g = "h"))] - | ^^^^^^^ +LL | #[proc_macro_derive(d14, attributes(a = ""))] + | ^^^^^^ error: must only be one word - --> $DIR/attribute.rs:46:35 + --> $DIR/attribute.rs:66:37 | -LL | #[proc_macro_derive(i, attributes(j(k)))] - | ^^^^ +LL | #[proc_macro_derive(d15, attributes(m::a))] + | ^^^^ -error: attribute must have either one or two arguments - --> $DIR/attribute.rs:52:1 +error: must only be one word + --> $DIR/attribute.rs:70:37 + | +LL | #[proc_macro_derive(d16, attributes(a(b)))] + | ^^^^ + +error: `self` cannot be a name of derive helper attribute + --> $DIR/attribute.rs:74:37 | -LL | #[proc_macro_derive(l, attributes(m), n)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[proc_macro_derive(d17, attributes(self))] + | ^^^^ error: attribute must be of the form `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` - --> $DIR/attribute.rs:8:1 + --> $DIR/attribute.rs:9:1 | LL | #[proc_macro_derive] | ^^^^^^^^^^^^^^^^^^^^ error: attribute must be of the form `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` - --> $DIR/attribute.rs:14:1 + --> $DIR/attribute.rs:13:1 | -LL | #[proc_macro_derive = "foo"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[proc_macro_derive = ""] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 18 previous errors diff --git a/src/test/ui/proc-macro/shadow-builtin.rs b/src/test/ui/proc-macro/shadow-builtin.rs deleted file mode 100644 index afcc0ebc3464c..0000000000000 --- a/src/test/ui/proc-macro/shadow-builtin.rs +++ /dev/null @@ -1,14 +0,0 @@ -// force-host -// no-prefer-dynamic - -#![crate_type = "proc-macro"] - -extern crate proc_macro; - -use proc_macro::TokenStream; - -#[proc_macro_derive(PartialEq)] -//~^ ERROR: cannot override a built-in #[derive] mode -pub fn foo(input: TokenStream) -> TokenStream { - input -} diff --git a/src/test/ui/proc-macro/shadow-builtin.stderr b/src/test/ui/proc-macro/shadow-builtin.stderr deleted file mode 100644 index 668579509dc3b..0000000000000 --- a/src/test/ui/proc-macro/shadow-builtin.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: cannot override a built-in #[derive] mode - --> $DIR/shadow-builtin.rs:10:21 - | -LL | #[proc_macro_derive(PartialEq)] - | ^^^^^^^^^ - -error: aborting due to previous error - From f8b17c5734cb2ad83b5b084091f5ce9ee5538773 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 17 Mar 2019 18:15:42 +0300 Subject: [PATCH 2/2] Restore APIs used by clippy --- src/libsyntax/attr/mod.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 857325681c660..4ce0dce7d54e1 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -832,3 +832,31 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) - krate } + +// APIs used by clippy and resurrected for beta +impl Attribute { + pub fn name(&self) -> Name { + self.path.segments.last().expect("empty path in attribute").ident.name + } +} +impl MetaItem { + pub fn name(&self) -> Name { + self.ident.segments.last().expect("empty path in attribute").ident.name + } + pub fn is_scoped(&self) -> Option { + if self.ident.segments.len() > 1 { + Some(self.ident.segments[0].ident) + } else { + None + } + } +} +impl NestedMetaItem { + pub fn word(&self) -> Option<&MetaItem> { + self.meta_item().and_then(|meta_item| if meta_item.is_word() { + Some(meta_item) + } else { + None + }) + } +}