diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index ec0424994075d..c1b04555f91b7 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -1062,7 +1062,7 @@ mod test { @diagnostic::DefaultEmitter as @diagnostic::Emitter); let cfg = build_configuration(sess); - assert!((attr::contains_name(cfg, "test"))); + assert!((attr::contains_attr(cfg, attr::AttrTest))); } // When the user supplies --test and --cfg test, don't implicitly add diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index 30d5b7780cf92..f9758c5ef37bd 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -409,7 +409,7 @@ pub fn building_library(options: &options, crate: &ast::Crate) -> bool { } } if options.test { return false } - match syntax::attr::first_attr_value_str_by_name(crate.attrs, "crate_type") { + match syntax::attr::first_attr_value(crate.attrs, syntax::attr::AttrCrateType) { Some(s) => "lib" == s || "rlib" == s || "dylib" == s || "staticlib" == s, _ => false } diff --git a/src/librustc/front/feature_gate.rs b/src/librustc/front/feature_gate.rs index 868b53c2465f2..9183e4258ead2 100644 --- a/src/librustc/front/feature_gate.rs +++ b/src/librustc/front/feature_gate.rs @@ -112,13 +112,11 @@ impl Visitor<()> for Context { } fn visit_item(&mut self, i: @ast::item, _:()) { - for attr in i.attrs.iter() { - if "thread_local" == attr.name() { - self.gate_feature("thread_local", i.span, - "`#[thread_local]` is an experimental feature, and does not \ - currently handle destructors. There is no corresponding \ - `#[task_local]` mapping to the task model"); - } + if attr::contains_attr(i.attrs, attr::AttrThreadLocal) { + self.gate_feature("thread_local", i.span, + "`#[thread_local]` is an experimental feature, and does not \ + currently handle destructors. There is no corresponding \ + `#[task_local]` mapping to the task model"); } match i.node { ast::item_enum(ref def, _) => { @@ -135,7 +133,7 @@ impl Visitor<()> for Context { } ast::item_foreign_mod(..) => { - if attr::contains_name(i.attrs, "link_args") { + if attr::contains_attr(i.attrs, attr::AttrLinkArgs) { self.gate_feature("link_args", i.span, "the `link_args` attribute is not portable \ across platforms, it is recommended to \ @@ -192,7 +190,7 @@ pub fn check_crate(sess: Session, crate: &ast::Crate) { }; for attr in crate.attrs.iter() { - if "feature" != attr.name() { continue } + if !attr.is_defined_attr(attr::AttrFeature) { continue } match attr.meta_item_list() { None => { diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs index a40f8183e1904..3d4fd0c738442 100644 --- a/src/librustc/front/std_inject.rs +++ b/src/librustc/front/std_inject.rs @@ -33,15 +33,15 @@ pub fn maybe_inject_libstd_ref(sess: Session, crate: ast::Crate) } fn use_std(crate: &ast::Crate) -> bool { - !attr::contains_name(crate.attrs, "no_std") + !attr::contains_attr(crate.attrs, attr::AttrNoStd) } fn use_uv(crate: &ast::Crate) -> bool { - !attr::contains_name(crate.attrs, "no_uv") + !attr::contains_attr(crate.attrs, attr::AttrNoUv) } fn no_prelude(attrs: &[ast::Attribute]) -> bool { - attr::contains_name(attrs, "no_implicit_prelude") + attr::contains_attr(attrs, attr::AttrNoImplicitPrelude) } fn spanned(x: T) -> codemap::Spanned { diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 192249d6435d5..f8700a7f956a3 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -52,7 +52,7 @@ pub fn modify_for_testing(sess: session::Session, // We generate the test harness when building in the 'test' // configuration, either with the '--test' or '--cfg test' // command line options. - let should_test = attr::contains_name(crate.config, "test"); + let should_test = attr::contains_attr(crate.config, attr::AttrTest); if should_test { generate_test_harness(sess, crate) @@ -120,7 +120,7 @@ impl fold::ast_fold for TestHarnessGenerator { if !*cx.sess.building_library { @ast::item { attrs: item.attrs.iter().filter_map(|attr| { - if "main" != attr.name() { + if !attr.is_defined_attr(attr::AttrMain) { Some(*attr) } else { None @@ -175,13 +175,13 @@ fn strip_test_functions(crate: ast::Crate) -> ast::Crate { // When not compiling with --test we should not compile the // #[test] functions config::strip_items(crate, |attrs| { - !attr::contains_name(attrs, "test") && - !attr::contains_name(attrs, "bench") + !attr::contains_attr(attrs, attr::AttrTest) && + !attr::contains_attr(attrs, attr::AttrBench) }) } fn is_test_fn(cx: @mut TestCtxt, i: @ast::item) -> bool { - let has_test_attr = attr::contains_name(i.attrs, "test"); + let has_test_attr = attr::contains_attr(i.attrs, attr::AttrTest); fn has_test_signature(i: @ast::item) -> bool { match &i.node { @@ -210,7 +210,7 @@ fn is_test_fn(cx: @mut TestCtxt, i: @ast::item) -> bool { } fn is_bench_fn(i: @ast::item) -> bool { - let has_bench_attr = attr::contains_name(i.attrs, "bench"); + let has_bench_attr = attr::contains_attr(i.attrs, attr::AttrBench); fn has_test_signature(i: @ast::item) -> bool { match i.node { @@ -244,7 +244,7 @@ fn is_ignored(cx: @mut TestCtxt, i: @ast::item) -> bool { } fn should_fail(i: @ast::item) -> bool { - attr::contains_name(i.attrs, "should_fail") + attr::contains_attr(i.attrs, attr::AttrShouldFail) } fn add_test_module(cx: &TestCtxt, m: &ast::_mod) -> ast::_mod { diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index c2d7878a081b6..b9af1bbd52e54 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -55,7 +55,7 @@ pub fn find_entry_point(session: Session, crate: &Crate, ast_map: ast_map::map) } // If the user wants no main function at all, then stop here. - if attr::contains_name(crate.attrs, "no_main") { + if attr::contains_attr(crate.attrs, attr::AttrNoMain) { *session.entry_type = Some(session::EntryNone); return } @@ -98,7 +98,7 @@ fn find_item(item: @item, ctxt: &mut EntryContext) { } } - if attr::contains_name(item.attrs, "main") { + if attr::contains_attr(item.attrs, attr::AttrMain) { if ctxt.attr_main_fn.is_none() { ctxt.attr_main_fn = Some((item.id, item.span)); } else { @@ -108,7 +108,7 @@ fn find_item(item: @item, ctxt: &mut EntryContext) { } } - if attr::contains_name(item.attrs, "start") { + if attr::contains_attr(item.attrs, attr::AttrStart) { if ctxt.start_fn.is_none() { ctxt.start_fn = Some((item.id, item.span)); } else { diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 195f7798eb0f5..7ecba0ce7210e 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -152,7 +152,7 @@ fn check_impl_of_trait(cx: &mut Context, it: @item, trait_ref: &trait_ref, self_ } fn check_item(cx: &mut Context, item: @item) { - if !attr::contains_name(item.attrs, "unsafe_destructor") { + if !attr::contains_attr(item.attrs, attr::AttrUnsafeDestructor) { match item.node { item_impl(_, Some(ref trait_ref), self_type, _) => { check_impl_of_trait(cx, item, trait_ref, self_type); diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index feee3583f717a..8c15af7e77335 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -488,9 +488,11 @@ impl<'a> Context<'a> { let old_is_doc_hidden = self.is_doc_hidden; self.is_doc_hidden = self.is_doc_hidden || - attrs.iter().any(|attr| ("doc" == attr.name() && match attr.meta_item_list() - { None => false, - Some(l) => attr::contains_name(l, "hidden") })); + attrs.iter().any(|attr| (attr.is_defined_attr(attr::AttrDoc) && + match attr.meta_item_list() { + None => false, + Some(l) => attr::contains_name(l, "hidden") + })); f(self); @@ -815,81 +817,39 @@ fn check_heap_item(cx: &Context, it: &ast::item) { } } -static crate_attrs: &'static [&'static str] = &[ - "crate_type", "feature", "no_uv", "no_main", "no_std", "pkgid", - "desc", "comment", "license", "copyright", // not used in rustc now -]; - - -static obsolete_attrs: &'static [(&'static str, &'static str)] = &[ - ("abi", "Use `extern \"abi\" fn` instead"), - ("auto_encode", "Use `#[deriving(Encodable)]` instead"), - ("auto_decode", "Use `#[deriving(Decodable)]` instead"), - ("fast_ffi", "Remove it"), - ("fixed_stack_segment", "Remove it"), - ("rust_stack", "Remove it"), -]; - -static other_attrs: &'static [&'static str] = &[ - // item-level - "address_insignificant", // can be crate-level too - "thread_local", // for statics - "allow", "deny", "forbid", "warn", // lint options - "deprecated", "experimental", "unstable", "stable", "locked", "frozen", //item stability - "crate_map", "cfg", "doc", "export_name", "link_section", "no_freeze", - "no_mangle", "no_send", "static_assert", "unsafe_no_drop_flag", - "packed", "simd", "repr", "deriving", "unsafe_destructor", "link", - - //mod-level - "path", "link_name", "link_args", "nolink", "macro_escape", "no_implicit_prelude", - - // fn-level - "test", "bench", "should_fail", "ignore", "inline", "lang", "main", "start", - "no_split_stack", "cold", - - // internal attribute: bypass privacy inside items - "!resolve_unexported", -]; - -fn check_crate_attrs_usage(cx: &Context, attrs: &[ast::Attribute]) { - - for attr in attrs.iter() { - let name = attr.node.value.name(); - let mut iter = crate_attrs.iter().chain(other_attrs.iter()); - if !iter.any(|other_attr| { name.equiv(other_attr) }) { - cx.span_lint(attribute_usage, attr.span, "unknown crate attribute"); - } - } -} - -fn check_attrs_usage(cx: &Context, attrs: &[ast::Attribute]) { +fn check_attrs_usage(cx: &Context, attrs: &[ast::Attribute], is_crate: bool) { // check if element has crate-level, obsolete, or any unknown attributes. for attr in attrs.iter() { - let name = attr.node.value.name(); - for crate_attr in crate_attrs.iter() { - if name.equiv(crate_attr) { - let msg = match attr.node.style { - ast::AttrOuter => "crate-level attribute should be an inner attribute: \ - add semicolon at end", - ast::AttrInner => "crate-level attribute should be in the root module", - }; - cx.span_lint(attribute_usage, attr.span, msg); - return; + match attr.to_defined_attr() { + Some(def_attr) => { + if !is_crate && def_attr.is_crate_attr() { + let msg = match attr.node.style { + ast::AttrOuter => "crate-level attribute should be an inner attribute: \ + add semicolon at end", + ast::AttrInner => "crate-level attribute should be in the root module", + }; + cx.span_lint(attribute_usage, attr.span, msg); + continue; + } + if def_attr.is_obsolete() { + let msg = match def_attr { + attr::AttrAbi => "Use `extern \"abi\" fn` instead", + attr::AttrAutoEncode => "Use `#[deriving(Encodable)]` instead", + attr::AttrAutoDecode => "Use `#[deriving(Decodable)]` instead", + attr::AttrFastFfi | attr::AttrFixedStackSegment | + attr::AttrRustStack => "Remove it", + _ => fail!(), + }; + cx.span_lint(attribute_usage, attr.span, + format!("obsolete attribute: {:s}", msg)); + continue; + } } - } - - for &(obs_attr, obs_alter) in obsolete_attrs.iter() { - if name.equiv(&obs_attr) { - cx.span_lint(attribute_usage, attr.span, - format!("obsolete attribute: {:s}", obs_alter)); - return; + None => { + cx.span_lint(attribute_usage, attr.span, "unknown attribute"); } } - - if !other_attrs.iter().any(|other_attr| { name.equiv(other_attr) }) { - cx.span_lint(attribute_usage, attr.span, "unknown attribute"); - } } } @@ -1094,13 +1054,7 @@ fn check_missing_doc_attrs(cx: &Context, _ => () } - let has_doc = attrs.iter().any(|a| { - match a.node.value.node { - ast::MetaNameValue(ref name, _) if "doc" == *name => true, - _ => false - } - }); - if !has_doc { + if !attr::contains_attr(attrs, attr::AttrDoc) { cx.span_lint(missing_doc, sp, format!("missing documentation for {}", desc)); } @@ -1242,7 +1196,7 @@ impl<'a> Visitor<()> for Context<'a> { check_item_non_uppercase_statics(cx, it); check_heap_item(cx, it); check_missing_doc_item(cx, it); - check_attrs_usage(cx, it.attrs); + check_attrs_usage(cx, it.attrs, false); cx.visit_ids(|v| v.visit_item(it, ())); @@ -1252,14 +1206,14 @@ impl<'a> Visitor<()> for Context<'a> { fn visit_foreign_item(&mut self, it: @ast::foreign_item, _: ()) { self.with_lint_attrs(it.attrs, |cx| { - check_attrs_usage(cx, it.attrs); + check_attrs_usage(cx, it.attrs, false); visit::walk_foreign_item(cx, it, ()); }) } fn visit_view_item(&mut self, i: &ast::view_item, _: ()) { self.with_lint_attrs(i.attrs, |cx| { - check_attrs_usage(cx, i.attrs); + check_attrs_usage(cx, i.attrs, false); visit::walk_view_item(cx, i, ()); }) } @@ -1313,7 +1267,7 @@ impl<'a> Visitor<()> for Context<'a> { visit::fk_method(_, _, m) => { self.with_lint_attrs(m.attrs, |cx| { check_missing_doc_method(cx, m); - check_attrs_usage(cx, m.attrs); + check_attrs_usage(cx, m.attrs, false); cx.visit_ids(|v| { v.visit_fn(fk, decl, body, span, id, ()); @@ -1329,7 +1283,7 @@ impl<'a> Visitor<()> for Context<'a> { fn visit_ty_method(&mut self, t: &ast::TypeMethod, _: ()) { self.with_lint_attrs(t.attrs, |cx| { check_missing_doc_ty_method(cx, t); - check_attrs_usage(cx, t.attrs); + check_attrs_usage(cx, t.attrs, false); visit::walk_ty_method(cx, t, ()); }) @@ -1350,7 +1304,7 @@ impl<'a> Visitor<()> for Context<'a> { fn visit_struct_field(&mut self, s: &ast::struct_field, _: ()) { self.with_lint_attrs(s.node.attrs, |cx| { check_missing_doc_struct_field(cx, s); - check_attrs_usage(cx, s.node.attrs); + check_attrs_usage(cx, s.node.attrs, false); visit::walk_struct_field(cx, s, ()); }) @@ -1359,7 +1313,7 @@ impl<'a> Visitor<()> for Context<'a> { fn visit_variant(&mut self, v: &ast::variant, g: &ast::Generics, _: ()) { self.with_lint_attrs(v.node.attrs, |cx| { check_missing_doc_variant(cx, v); - check_attrs_usage(cx, v.node.attrs); + check_attrs_usage(cx, v.node.attrs, false); visit::walk_variant(cx, v, g, ()); }) @@ -1411,7 +1365,7 @@ pub fn check_crate(tcx: ty::ctxt, visit::walk_crate(v, crate, ()); }); - check_crate_attrs_usage(cx, crate.attrs); + check_attrs_usage(cx, crate.attrs, true); // since the root module isn't visited as an item (because it isn't an item), warn for it // here. check_missing_doc_attrs(cx, None, crate.attrs, crate.span, "crate"); diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index ded8d11786a2e..1a95a43f8e4cb 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -605,7 +605,7 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> { fn visit_item(&mut self, item: @ast::item, _: ()) { // Do not check privacy inside items with the resolve_unexported // attribute. This is used for the test runner. - if attr::contains_name(item.attrs, "!resolve_unexported") { + if attr::contains_attr(item.attrs, attr::AttrResolveUnexported) { return; } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index d665d279a1759..1277994b75c12 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -31,7 +31,7 @@ use syntax::visit; // Returns true if the given set of attributes contains the `#[inline]` // attribute. fn attributes_specify_inlining(attrs: &[ast::Attribute]) -> bool { - attr::contains_name(attrs, "inline") + attr::contains_attr(attrs, attr::AttrInline) } // Returns true if the given set of generics implies that the item it's @@ -316,8 +316,7 @@ impl ReachableContext { // Statics with insignificant addresses are not reachable // because they're inlined specially into all other crates. ast::item_static(..) => { - if attr::contains_name(item.attrs, - "address_insignificant") { + if attr::contains_attr(item.attrs, attr::AttrAddressInsignificant) { self.reachable_symbols.remove(&search_item); } } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index d6fc48b52ea2c..06ad01c81de36 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -481,11 +481,11 @@ pub fn set_llvm_fn_attrs(attrs: &[ast::Attribute], llfn: ValueRef) { } // Add the no-split-stack attribute if requested - if contains_name(attrs, "no_split_stack") { + if contains_attr(attrs, AttrNoSplitStack) { set_no_split_stack(llfn); } - if contains_name(attrs, "cold") { + if contains_attr(attrs, AttrCold) { unsafe { llvm::LLVMAddColdAttribute(llfn) } } } @@ -2199,7 +2199,7 @@ pub fn trans_item(ccx: @mut CrateContext, item: &ast::item) { consts::trans_const(ccx, m, item.id); // Do static_assert checking. It can't really be done much earlier // because we need to get the value of the bool out of LLVM - if attr::contains_name(item.attrs, "static_assert") { + if attr::contains_attr(item.attrs, attr::AttrStaticAssert) { if m == ast::MutMutable { ccx.sess.span_fatal(expr.span, "cannot have static_assert on a mutable \ @@ -2416,12 +2416,12 @@ pub fn item_path(ccx: &CrateContext, id: &ast::NodeId) -> path { } fn exported_name(ccx: &mut CrateContext, path: path, ty: ty::t, attrs: &[ast::Attribute]) -> ~str { - match attr::first_attr_value_str_by_name(attrs, "export_name") { + match attr::first_attr_value(attrs, attr::AttrExportName) { // Use provided name Some(name) => name.to_owned(), // Don't mangle - _ if attr::contains_name(attrs, "no_mangle") + _ if attr::contains_attr(attrs, attr::AttrNoMangle) => path_elt_to_str(*path.last(), token::get_ident_interner()), // Usual name mangling @@ -2479,8 +2479,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef { // Apply the `unnamed_addr` attribute if // requested - if attr::contains_name(i.attrs, - "address_insignificant"){ + if attr::contains_attr(i.attrs, attr::AttrAddressInsignificant){ if ccx.reachable.contains(&id) { ccx.sess.span_bug(i.span, "insignificant static is \ @@ -2507,7 +2506,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef { inlineable = true; } - if attr::contains_name(i.attrs, "thread_local") { + if attr::contains_attr(i.attrs, attr::AttrThreadLocal) { lib::llvm::set_thread_local(g, true); } @@ -2536,7 +2535,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef { _ => fail!("get_item_val: weird result in table") }; - match (attr::first_attr_value_str_by_name(i.attrs, "link_section")) { + match (attr::first_attr_value(i.attrs, attr::AttrLinkSection)) { Some(sect) => unsafe { sect.with_c_str(|buf| { llvm::LLVMSetSection(v, buf); @@ -2582,7 +2581,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef { // with weak linkage, but if we're building a // library then we've already declared the crate map // so use that instead. - if attr::contains_name(ni.attrs, "crate_map") { + if attr::contains_attr(ni.attrs, attr::AttrCrateMap) { if *ccx.sess.building_library { let s = "_rust_crate_map_toplevel"; let g = unsafe { diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 2a0840a0ef8ad..06f3ff77b21eb 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -733,10 +733,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: @mut CrateContext, // the massive simplifications that have occurred. pub fn link_name(ccx: &CrateContext, i: @ast::foreign_item) -> @str { - match attr::first_attr_value_str_by_name(i.attrs, "link_name") { - None => ccx.sess.str_of(i.ident), - Some(ln) => ln, - } + attr::first_attr_value(i.attrs, attr::AttrLinkName).unwrap_or(ccx.sess.str_of(i.ident)) } fn foreign_signature(ccx: &mut CrateContext, fn_sig: &ty::FnSig, arg_tys: &[ty::t]) diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs index a3f6b7db326aa..1c2f3f473c565 100644 --- a/src/librustc/middle/trans/inline.rs +++ b/src/librustc/middle/trans/inline.rs @@ -71,8 +71,7 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::DefId) let g = get_item_val(ccx, item.id); // see the comment in get_item_val() as to why this check is // performed here. - if !attr::contains_name(item.attrs, - "address_insignificant") { + if !attr::contains_attr(item.attrs, attr::AttrAddressInsignificant) { SetLinkage(g, AvailableExternallyLinkage); } } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index ac5254f1abafc..c914e6a62c0a8 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -22,6 +22,172 @@ use pkgid::PkgId; use std::hashmap::HashSet; +#[deriving(Eq)] +pub enum DefinedAttr { + // crate-level + AttrCrateType, + AttrFeature, + AttrNoUv, + AttrNoMain, + AttrNoStd, + AttrPkgid, + AttrDesc, + AttrComment, + AttrLicense, + AttrCopyright, + + // item-level + AttrAddressInsignificant, + AttrThreadLocal, // for statics + AttrAllow, // lint options + AttrDeny, + AttrForbid, + AttrWarn, + AttrDeprecated, //item stability + AttrExperimental, + AttrUnstable, + AttrStable, + AttrLocked, + AttrFrozen, + AttrCrateMap, + AttrCfg, + AttrDoc, + AttrExportName, + AttrLinkSection, + AttrNoFreeze, + AttrNoMangle, + AttrNoSend, + AttrStaticAssert, + AttrUnsafeNoDropFlag, + AttrPacked, + AttrSimd, + AttrRepr, + AttrDeriving, + AttrUnsafeDestructor, + AttrLink, + + //mod-level + AttrPath, + AttrLinkName, + AttrLinkArgs, + AttrNolink, + AttrMacroEscape, + AttrNoImplicitPrelude, + + // fn-level + AttrTest, + AttrBench, + AttrShouldFail, + AttrIgnore, + AttrInline, + AttrLang, + AttrMain, + AttrStart, + AttrNoSplitStack, + AttrCold, + + // internal attribute: bypass privacy inside items + AttrResolveUnexported, + + // obsolete + AttrAbi, + AttrAutoEncode, + AttrAutoDecode, + AttrRustStack, + AttrFastFfi, + AttrFixedStackSegment, +} + +impl FromStr for DefinedAttr { + fn from_str(s: &str) -> Option { + let v = match s { + "crate_type" => AttrCrateType, + "feature" => AttrFeature, + "no_uv" => AttrNoUv, + "no_main" => AttrNoMain, + "no_std" => AttrNoStd, + "pkgid" => AttrPkgid, + "desc" => AttrDesc, + "comment" => AttrComment, + "license" => AttrLicense, + "copyright" => AttrCopyright, + "address_insignificant" => AttrAddressInsignificant, + "thread_local" => AttrThreadLocal, + "allow" => AttrAllow, + "deny" => AttrDeny, + "forbid" => AttrForbid, + "warn" => AttrWarn, + "deprecated" => AttrDeprecated, + "experimental" => AttrExperimental, + "unstable" => AttrUnstable, + "stable" => AttrStable, + "locked" => AttrLocked, + "frozen" => AttrFrozen, + "crate_map" => AttrCrateMap, + "cfg" => AttrCfg, + "doc" => AttrDoc, + "export_name" => AttrExportName, + "link_section" => AttrLinkSection, + "no_freeze" => AttrNoFreeze, + "no_mangle" => AttrNoMangle, + "no_send" => AttrNoSend, + "static_assert" => AttrStaticAssert, + "unsafe_no_drop_flag" => AttrUnsafeNoDropFlag, + "packed" => AttrPacked, + "simd" => AttrSimd, + "repr" => AttrRepr, + "deriving" => AttrDeriving, + "unsafe_destructor" => AttrUnsafeDestructor, + "link" => AttrLink, + "path" => AttrPath, + "link_name" => AttrLinkName, + "link_args" => AttrLinkArgs, + "nolink" => AttrNolink, + "macro_escape" => AttrMacroEscape, + "no_implicit_prelude" => AttrNoImplicitPrelude, + "test" => AttrTest, + "bench" => AttrBench, + "should_fail" => AttrShouldFail, + "ignore" => AttrIgnore, + "inline" => AttrInline, + "lang" => AttrLang, + "main" => AttrMain, + "start" => AttrStart, + "no_split_stack" => AttrNoSplitStack, + "cold" => AttrCold, + "!resolve_unexported" => AttrResolveUnexported, + + "abi" => AttrAbi, + "auto_encode" => AttrAutoEncode, + "auto_decode" => AttrAutoDecode, + "fast_ffi" => AttrFastFfi, + "rust_stack" => AttrRustStack, + "fixed_stack_segment" => AttrFixedStackSegment, + + _ => return None, + }; + Some(v) + } +} + +impl DefinedAttr { + pub fn is_crate_attr(&self) -> bool { + match *self { + AttrCrateType | AttrFeature | AttrNoUv | AttrNoMain | AttrNoStd | + AttrPkgid | AttrDesc | AttrComment | AttrLicense | AttrCopyright => true, + _ => false, + } + } + + pub fn is_obsolete(&self) -> bool { + match *self { + AttrAbi | AttrAutoEncode | AttrAutoDecode | AttrRustStack | + AttrFastFfi | AttrFixedStackSegment => true, + _ => false, + } + } +} + pub trait AttrMetaMethods { // This could be changed to `fn check_name(&self, name: @str) -> // bool` which would facilitate a side table recording which @@ -44,6 +210,14 @@ pub trait AttrMetaMethods { * a tuple containing the name and string value, otherwise `None` */ fn name_str_pair(&self) -> Option<(@str, @str)>; + + fn to_defined_attr(&self) -> Option { + FromStr::from_str(self.name()) + } + + fn is_defined_attr(&self, attr: DefinedAttr) -> bool { + self.to_defined_attr() == Some(attr) + } } impl AttrMetaMethods for Attribute { @@ -184,10 +358,12 @@ pub fn contains_name(metas: &[AM], name: &str) -> bool { }) } -pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str) - -> Option<@str> { - attrs.iter() - .find(|at| name == at.name()) +pub fn contains_attr(attrs: &[AM], attr: DefinedAttr) -> bool { + attrs.iter().any(|item| item.is_defined_attr(attr)) +} + +pub fn first_attr_value(attrs: &[Attribute], attr: DefinedAttr) -> Option<@str> { + attrs.iter().find(|at| at.is_defined_attr(attr)) .and_then(|at| at.value_str()) } @@ -227,7 +403,7 @@ pub fn sort_meta_items(items: &[@MetaItem]) -> ~[@MetaItem] { */ pub fn find_linkage_metas(attrs: &[Attribute]) -> ~[@MetaItem] { let mut result = ~[]; - for attr in attrs.iter().filter(|at| "link" == at.name()) { + for attr in attrs.iter().filter(|at| at.is_defined_attr(AttrLink)) { match attr.meta().node { MetaList(_, ref items) => result.push_all(*items), _ => () @@ -237,7 +413,7 @@ pub fn find_linkage_metas(attrs: &[Attribute]) -> ~[@MetaItem] { } pub fn find_pkgid(attrs: &[Attribute]) -> Option { - match first_attr_value_str_by_name(attrs, "pkgid") { + match first_attr_value(attrs, AttrPkgid) { None => None, Some(id) => from_str::(id), } @@ -286,7 +462,7 @@ pub fn test_cfg> // this doesn't work. let some_cfg_matches = metas.any(|mi| { debug!("testing name: {}", mi.name()); - if "cfg" == mi.name() { // it is a #[cfg()] attribute + if mi.is_defined_attr(AttrCfg) { // it is a #[cfg()] attribute debug!("is cfg"); no_cfgs = false; // only #[cfg(...)] ones are understood. diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index a6e45c7e1bbb3..5bfb250e0a215 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -292,7 +292,7 @@ pub fn expand_item(extsbox: @mut SyntaxEnv, // does this attribute list contain "macro_escape" ? pub fn contains_macro_escape(attrs: &[ast::Attribute]) -> bool { - attr::contains_name(attrs, "macro_escape") + attr::contains_attr(attrs, attr::AttrMacroEscape) } // Support for item-position macro invocations, exactly the same diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index aa37d859d7971..afc3db071fc40 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -60,12 +60,12 @@ use ast::{unnamed_field, UnsafeBlock, unsafe_fn, view_item}; use ast::{view_item_, view_item_extern_mod, view_item_use}; use ast::{view_path, view_path_glob, view_path_list, view_path_simple}; use ast::visibility; +use attr; use ast; use ast_util::{as_prec, operator_prec}; use ast_util; use codemap::{Span, BytePos, Spanned, spanned, mk_sp}; use codemap; -use parse::attr::parser_attr; use parse::classify; use parse::common::{SeqSep, seq_sep_none}; use parse::common::{seq_sep_trailing_disallowed, seq_sep_trailing_allowed}; @@ -4194,11 +4194,7 @@ impl Parser { fn push_mod_path(&self, id: Ident, attrs: &[Attribute]) { let default_path = token::interner_get(id.name); - let file_path = match ::attr::first_attr_value_str_by_name(attrs, - "path") { - Some(d) => d, - None => default_path - }; + let file_path = attr::first_attr_value(attrs, attr::AttrPath).unwrap_or(default_path); self.mod_path_stack.push(file_path) } @@ -4217,8 +4213,7 @@ impl Parser { let mod_path_stack = &*self.mod_path_stack; let mod_path = Path::new(".").join_many(*mod_path_stack); let dir_path = prefix.join(&mod_path); - let file_path = match ::attr::first_attr_value_str_by_name( - outer_attrs, "path") { + let file_path = match attr::first_attr_value(outer_attrs, attr::AttrPath) { Some(d) => dir_path.join(d), None => { let mod_name = token::interner_get(id.name).to_owned(); diff --git a/src/test/compile-fail/lint-unknown-attr.rs b/src/test/compile-fail/lint-unknown-attr.rs index ce83ba464c06e..10c12d54b3ed9 100644 --- a/src/test/compile-fail/lint-unknown-attr.rs +++ b/src/test/compile-fail/lint-unknown-attr.rs @@ -13,7 +13,7 @@ #[deny(attribute_usage)]; -#[mutable_doc]; //~ ERROR: unknown crate attribute +#[mutable_doc]; //~ ERROR: unknown attribute #[dance] mod a {} //~ ERROR: unknown attribute