diff options
| author | bors <bors@rust-lang.org> | 2016-08-30 00:36:19 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-08-30 00:36:19 -0700 |
| commit | 71ee82a8aa0c02fc2c73e84f40bdb55512d10938 (patch) | |
| tree | e2ead4306f12a3f92170850edc1176667765a9d0 /src/libsyntax | |
| parent | addb7537620feb228d6c9fe149b9c069d3686199 (diff) | |
| parent | 02f081c0b53cad0bcfe1d20ebb892f06ffa996ff (diff) | |
| download | rust-71ee82a8aa0c02fc2c73e84f40bdb55512d10938.tar.gz rust-71ee82a8aa0c02fc2c73e84f40bdb55512d10938.zip | |
Auto merge of #36066 - jseyfried:rollup, r=Manishearth
Batch up libsyntax breaking changes Batch of the following syntax-[breaking-change] changes: - #35591: Add a field `span: Span` to `ast::Generics`. - #35618: Remove variant `Mod` of `ast::PathListItemKind` and refactor the remaining variant `ast::PathListKind::Ident` to a struct `ast::PathListKind_`. - #35480: Change uses of `Constness` in the AST to `Spanned<Constness>`. - c.f. `MethodSig`, `ItemKind` - #35728: Refactor `cx.pat_enum()` into `cx.pat_tuple_struct()` and `cx.pat_path()`. - #35850: Generalize the elements of lists in attributes from `MetaItem` to a new type `NestedMetaItem` that can represent a `MetaItem` or a literal. - #35917: Remove traits `AttrMetaMethods`, `AttributeMethods`, and `AttrNestedMetaItemMethods`. - Besides removing imports of these traits, this won't cause fallout. - Add a variant `Union` to `ItemKind` to future proof for `union` (c.f. #36016). - Remove inherent methods `attrs` and `fold_attrs` of `Annotatable`. - Use methods `attrs` and `map_attrs` of `HasAttrs` instead. r? @Manishearth
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 113 | ||||
| -rw-r--r-- | src/libsyntax/attr.rs | 387 | ||||
| -rw-r--r-- | src/libsyntax/config.rs | 40 | ||||
| -rw-r--r-- | src/libsyntax/diagnostic_list.rs | 18 | ||||
| -rw-r--r-- | src/libsyntax/ext/base.rs | 7 | ||||
| -rw-r--r-- | src/libsyntax/ext/build.rs | 59 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 1 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 57 | ||||
| -rw-r--r-- | src/libsyntax/fold.rs | 42 | ||||
| -rw-r--r-- | src/libsyntax/parse/attr.rs | 64 | ||||
| -rw-r--r-- | src/libsyntax/parse/mod.rs | 12 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 56 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 56 | ||||
| -rw-r--r-- | src/libsyntax/test.rs | 11 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 9 |
15 files changed, 590 insertions, 342 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f8a5cb0b04a..fcb99444957 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -336,7 +336,7 @@ pub struct TyParam { pub id: NodeId, pub bounds: TyParamBounds, pub default: Option<P<Ty>>, - pub span: Span + pub span: Span, } /// Represents lifetimes and type parameters attached to a declaration @@ -346,6 +346,7 @@ pub struct Generics { pub lifetimes: Vec<LifetimeDef>, pub ty_params: P<[TyParam]>, pub where_clause: WhereClause, + pub span: Span, } impl Generics { @@ -368,7 +369,8 @@ impl Default for Generics { where_clause: WhereClause { id: DUMMY_NODE_ID, predicates: Vec::new(), - } + }, + span: DUMMY_SP, } } } @@ -439,6 +441,22 @@ pub struct Crate { pub exported_macros: Vec<MacroDef>, } +/// A spanned compile-time attribute list item. +pub type NestedMetaItem = Spanned<NestedMetaItemKind>; + +/// Possible values inside of compile-time attribute lists. +/// +/// E.g. the '..' in `#[name(..)]`. +#[derive(Clone, Eq, RustcEncodable, RustcDecodable, Hash, Debug, PartialEq)] +pub enum NestedMetaItemKind { + /// A full MetaItem, for recursive meta items. + MetaItem(P<MetaItem>), + /// A literal. + /// + /// E.g. "foo", 64, true + Literal(Lit), +} + /// A spanned compile-time attribute item. /// /// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]` @@ -456,7 +474,7 @@ pub enum MetaItemKind { /// List meta item. /// /// E.g. `derive(..)` as in `#[derive(..)]` - List(InternedString, Vec<P<MetaItem>>), + List(InternedString, Vec<NestedMetaItem>), /// Name value meta item. /// /// E.g. `feature = "foo"` as in `#[feature = "foo"]` @@ -472,19 +490,21 @@ impl PartialEq for MetaItemKind { Word(ref no) => (*ns) == (*no), _ => false }, + List(ref ns, ref miss) => match *other { + List(ref no, ref miso) => { + ns == no && + miss.iter().all(|mi| { + miso.iter().any(|x| x.node == mi.node) + }) + } + _ => false + }, NameValue(ref ns, ref vs) => match *other { NameValue(ref no, ref vo) => { (*ns) == (*no) && vs.node == vo.node } _ => false }, - List(ref ns, ref miss) => match *other { - List(ref no, ref miso) => { - ns == no && - miss.iter().all(|mi| miso.iter().any(|x| x.node == mi.node)) - } - _ => false - } } } } @@ -1105,6 +1125,30 @@ impl LitKind { _ => false, } } + + /// Returns true if this literal has no suffix. Note: this will return true + /// for literals with prefixes such as raw strings and byte strings. + pub fn is_unsuffixed(&self) -> bool { + match *self { + // unsuffixed variants + LitKind::Str(..) => true, + LitKind::ByteStr(..) => true, + LitKind::Byte(..) => true, + LitKind::Char(..) => true, + LitKind::Int(_, LitIntType::Unsuffixed) => true, + LitKind::FloatUnsuffixed(..) => true, + LitKind::Bool(..) => true, + // suffixed variants + LitKind::Int(_, LitIntType::Signed(..)) => false, + LitKind::Int(_, LitIntType::Unsigned(..)) => false, + LitKind::Float(..) => false, + } + } + + /// Returns true if this literal has a suffix. + pub fn is_suffixed(&self) -> bool { + !self.is_unsuffixed() + } } // NB: If you change this, you'll probably want to change the corresponding @@ -1120,7 +1164,7 @@ pub struct MutTy { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct MethodSig { pub unsafety: Unsafety, - pub constness: Constness, + pub constness: Spanned<Constness>, pub abi: Abi, pub decl: P<FnDecl>, pub generics: Generics, @@ -1624,42 +1668,14 @@ pub struct Variant_ { pub type Variant = Spanned<Variant_>; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub enum PathListItemKind { - Ident { - name: Ident, - /// renamed in list, e.g. `use foo::{bar as baz};` - rename: Option<Ident>, - id: NodeId - }, - Mod { - /// renamed in list, e.g. `use foo::{self as baz};` - rename: Option<Ident>, - id: NodeId - } -} - -impl PathListItemKind { - pub fn id(&self) -> NodeId { - match *self { - PathListItemKind::Ident { id, .. } | PathListItemKind::Mod { id, .. } => id - } - } - - pub fn name(&self) -> Option<Ident> { - match *self { - PathListItemKind::Ident { name, .. } => Some(name), - PathListItemKind::Mod { .. } => None, - } - } - - pub fn rename(&self) -> Option<Ident> { - match *self { - PathListItemKind::Ident { rename, .. } | PathListItemKind::Mod { rename, .. } => rename - } - } +pub struct PathListItem_ { + pub name: Ident, + /// renamed in list, e.g. `use foo::{bar as baz};` + pub rename: Option<Ident>, + pub id: NodeId, } -pub type PathListItem = Spanned<PathListItemKind>; +pub type PathListItem = Spanned<PathListItem_>; pub type ViewPath = Spanned<ViewPath_>; @@ -1846,7 +1862,7 @@ pub enum ItemKind { /// A function declaration (`fn` or `pub fn`). /// /// E.g. `fn foo(bar: usize) -> usize { .. }` - Fn(P<FnDecl>, Unsafety, Constness, Abi, Generics, P<Block>), + Fn(P<FnDecl>, Unsafety, Spanned<Constness>, Abi, Generics, P<Block>), /// A module declaration (`mod` or `pub mod`). /// /// E.g. `mod foo;` or `mod foo { .. }` @@ -1867,6 +1883,10 @@ pub enum ItemKind { /// /// E.g. `struct Foo<A> { x: A }` Struct(VariantData, Generics), + /// A union definition (`union` or `pub union`). + /// + /// E.g. `union Foo<A, B> { x: A, y: B }` + Union(VariantData, Generics), // FIXME: not yet implemented /// A Trait declaration (`trait` or `pub trait`). /// /// E.g. `trait Foo { .. }` or `trait Foo<T> { .. }` @@ -1903,6 +1923,7 @@ impl ItemKind { ItemKind::Ty(..) => "type alias", ItemKind::Enum(..) => "enum", ItemKind::Struct(..) => "struct", + ItemKind::Union(..) => "union", ItemKind::Trait(..) => "trait", ItemKind::Mac(..) | ItemKind::Impl(..) | diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index b622f6861b3..6060ff529f2 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -15,9 +15,10 @@ pub use self::ReprAttr::*; pub use self::IntType::*; use ast; -use ast::{AttrId, Attribute, Attribute_, MetaItem, MetaItemKind}; -use ast::{Expr, Item, Local, Stmt, StmtKind}; -use codemap::{respan, spanned, dummy_spanned, Spanned}; +use ast::{AttrId, Attribute, Attribute_}; +use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; +use ast::{Lit, Expr, Item, Local, Stmt, StmtKind}; +use codemap::{respan, spanned, dummy_spanned}; use syntax_pos::{Span, BytePos, DUMMY_SP}; use errors::Handler; use feature_gate::{Features, GatedCfg}; @@ -40,6 +41,7 @@ enum AttrError { MissingSince, MissingFeature, MultipleStabilityLevels, + UnsupportedLiteral } fn handle_errors(diag: &Handler, span: Span, error: AttrError) { @@ -52,10 +54,12 @@ fn handle_errors(diag: &Handler, span: Span, error: AttrError) { AttrError::MissingFeature => span_err!(diag, span, E0546, "missing 'feature'"), AttrError::MultipleStabilityLevels => span_err!(diag, span, E0544, "multiple stability levels"), + AttrError::UnsupportedLiteral => span_err!(diag, span, E0565, "unsupported literal"), } } pub fn mark_used(attr: &Attribute) { + debug!("Marking {:?} as used.", attr); let AttrId(id) = attr.node.id; USED_ATTRS.with(|slot| { let idx = (id / 64) as usize; @@ -77,60 +81,120 @@ pub fn is_used(attr: &Attribute) -> bool { }) } -pub trait AttrMetaMethods { - fn check_name(&self, name: &str) -> bool { - name == &self.name()[..] +impl NestedMetaItem { + /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem. + pub fn meta_item(&self) -> Option<&P<MetaItem>> { + match self.node { + NestedMetaItemKind::MetaItem(ref item) => Some(&item), + _ => None + } + } + + /// Returns the Lit if self is a NestedMetaItemKind::Literal. + pub fn literal(&self) -> Option<&Lit> { + match self.node { + NestedMetaItemKind::Literal(ref lit) => Some(&lit), + _ => None + } } - /// Retrieve the name of the meta item, e.g. `foo` in `#[foo]`, - /// `#[foo="bar"]` and `#[foo(bar)]` - fn name(&self) -> InternedString; + /// Returns the Span for `self`. + pub fn span(&self) -> Span { + self.span + } + + /// Returns true if this list item is a MetaItem with a name of `name`. + pub fn check_name(&self, name: &str) -> bool { + 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<InternedString> { + self.meta_item().and_then(|meta_item| Some(meta_item.name())) + } + + /// Gets the string value if self is a MetaItem and the MetaItem is a + /// MetaItemKind::NameValue variant containing a string, otherwise None. + pub fn value_str(&self) -> Option<InternedString> { + self.meta_item().and_then(|meta_item| meta_item.value_str()) + } + + /// Returns a MetaItem if self is a MetaItem with Kind Word. + pub fn word(&self) -> Option<&P<MetaItem>> { + self.meta_item().and_then(|meta_item| if meta_item.is_word() { + Some(meta_item) + } else { + None + }) + } - /// Gets the string value if self is a MetaItemKind::NameValue variant - /// containing a string, otherwise None. - fn value_str(&self) -> Option<InternedString>; /// Gets a list of inner meta items from a list MetaItem type. - fn meta_item_list(&self) -> Option<&[P<MetaItem>]>; + pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { + self.meta_item().and_then(|meta_item| meta_item.meta_item_list()) + } - /// Indicates if the attribute is a Word. - fn is_word(&self) -> bool; + /// Returns `true` if the variant is MetaItem. + pub fn is_meta_item(&self) -> bool { + self.meta_item().is_some() + } - /// Indicates if the attribute is a Value String. - fn is_value_str(&self) -> bool { + /// Returns `true` if the variant is Literal. + pub fn is_literal(&self) -> bool { + self.literal().is_some() + } + + /// Returns `true` if self is a MetaItem and the meta item is a word. + pub fn is_word(&self) -> bool { + self.word().is_some() + } + + /// Returns `true` if self is a MetaItem and the meta item is a ValueString. + pub fn is_value_str(&self) -> bool { self.value_str().is_some() } - /// Indicates if the attribute is a Meta-Item List. - fn is_meta_item_list(&self) -> bool { + /// Returns `true` if self is a MetaItem and the meta item is a list. + pub fn is_meta_item_list(&self) -> bool { self.meta_item_list().is_some() } - - fn span(&self) -> Span; } -impl AttrMetaMethods for Attribute { - fn check_name(&self, name: &str) -> bool { +impl Attribute { + pub fn check_name(&self, name: &str) -> bool { let matches = name == &self.name()[..]; if matches { mark_used(self); } matches } - fn name(&self) -> InternedString { self.meta().name() } - fn value_str(&self) -> Option<InternedString> { + + pub fn name(&self) -> InternedString { self.meta().name() } + + pub fn value_str(&self) -> Option<InternedString> { self.meta().value_str() } - fn meta_item_list(&self) -> Option<&[P<MetaItem>]> { + + pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { self.meta().meta_item_list() } - fn is_word(&self) -> bool { self.meta().is_word() } + pub fn is_word(&self) -> bool { self.meta().is_word() } + + pub fn span(&self) -> Span { self.meta().span } + + pub fn is_meta_item_list(&self) -> bool { + self.meta_item_list().is_some() + } - fn span(&self) -> Span { self.meta().span } + /// Indicates if the attribute is a Value String. + pub fn is_value_str(&self) -> bool { + self.value_str().is_some() + } } -impl AttrMetaMethods for MetaItem { - fn name(&self) -> InternedString { +impl MetaItem { + pub fn name(&self) -> InternedString { match self.node { MetaItemKind::Word(ref n) => (*n).clone(), MetaItemKind::NameValue(ref n, _) => (*n).clone(), @@ -138,7 +202,7 @@ impl AttrMetaMethods for MetaItem { } } - fn value_str(&self) -> Option<InternedString> { + pub fn value_str(&self) -> Option<InternedString> { match self.node { MetaItemKind::NameValue(_, ref v) => { match v.node { @@ -150,53 +214,45 @@ impl AttrMetaMethods for MetaItem { } } - fn meta_item_list(&self) -> Option<&[P<MetaItem>]> { + pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { match self.node { MetaItemKind::List(_, ref l) => Some(&l[..]), _ => None } } - fn is_word(&self) -> bool { + pub fn is_word(&self) -> bool { match self.node { MetaItemKind::Word(_) => true, _ => false, } } - fn span(&self) -> Span { self.span } -} + pub fn span(&self) -> Span { self.span } -// Annoying, but required to get test_cfg to work -impl AttrMetaMethods for P<MetaItem> { - fn name(&self) -> InternedString { (**self).name() } - fn value_str(&self) -> Option<InternedString> { (**self).value_str() } - fn meta_item_list(&self) -> Option<&[P<MetaItem>]> { - (**self).meta_item_list() + pub fn check_name(&self, name: &str) -> bool { + name == &self.name()[..] } - fn is_word(&self) -> bool { (**self).is_word() } - fn is_value_str(&self) -> bool { (**self).is_value_str() } - fn is_meta_item_list(&self) -> bool { (**self).is_meta_item_list() } - fn span(&self) -> Span { (**self).span() } -} + pub fn is_value_str(&self) -> bool { + self.value_str().is_some() + } -pub trait AttributeMethods { - fn meta(&self) -> &MetaItem; - fn with_desugared_doc<T, F>(&self, f: F) -> T where - F: FnOnce(&Attribute) -> T; + pub fn is_meta_item_list(&self) -> bool { + self.meta_item_list().is_some() + } } -impl AttributeMethods for Attribute { +impl Attribute { /// Extract the MetaItem from inside this Attribute. - fn meta(&self) -> &MetaItem { + pub fn meta(&self) -> &MetaItem { &self.node.value } /// Convert self to a normal #[doc="foo"] comment, if it is a /// comment like `///` or `/** */`. (Returns self unchanged for /// non-sugared doc attributes.) - fn with_desugared_doc<T, F>(&self, f: F) -> T where + pub fn with_desugared_doc<T, F>(&self, f: F) -> T where F: FnOnce(&Attribute) -> T, { if self.node.is_sugared_doc { @@ -229,10 +285,14 @@ pub fn mk_name_value_item(name: InternedString, value: ast::Lit) mk_spanned_name_value_item(DUMMY_SP, name, value) } -pub fn mk_list_item(name: InternedString, items: Vec<P<MetaItem>>) -> P<MetaItem> { +pub fn mk_list_item(name: InternedString, items: Vec<NestedMetaItem>) -> P<MetaItem> { mk_spanned_list_item(DUMMY_SP, name, items) } +pub fn mk_list_word_item(name: InternedString) -> ast::NestedMetaItem { + dummy_spanned(NestedMetaItemKind::MetaItem(mk_spanned_word_item(DUMMY_SP, name))) +} + pub fn mk_word_item(name: InternedString) -> P<MetaItem> { mk_spanned_word_item(DUMMY_SP, name) } @@ -242,7 +302,7 @@ pub fn mk_spanned_name_value_item(sp: Span, name: InternedString, value: ast::Li P(respan(sp, MetaItemKind::NameValue(name, value))) } -pub fn mk_spanned_list_item(sp: Span, name: InternedString, items: Vec<P<MetaItem>>) +pub fn mk_spanned_list_item(sp: Span, name: InternedString, items: Vec<NestedMetaItem>) -> P<MetaItem> { P(respan(sp, MetaItemKind::List(name, items))) } @@ -332,9 +392,17 @@ pub fn contains(haystack: &[P<MetaItem>], needle: &MetaItem) -> bool { }) } -pub fn contains_name<AM: AttrMetaMethods>(metas: &[AM], name: &str) -> bool { +pub fn list_contains_name(items: &[NestedMetaItem], name: &str) -> bool { + debug!("attr::list_contains_name (name={})", name); + items.iter().any(|item| { + debug!(" testing: {:?}", item.name()); + item.check_name(name) + }) +} + +pub fn contains_name(attrs: &[Attribute], name: &str) -> bool { debug!("attr::contains_name (name={})", name); - metas.iter().any(|item| { + attrs.iter().any(|item| { debug!(" testing: {}", item.name()); item.check_name(name) }) @@ -357,27 +425,6 @@ pub fn last_meta_item_value_str_by_name(items: &[P<MetaItem>], name: &str) /* Higher-level applications */ -pub fn sort_meta_items(items: Vec<P<MetaItem>>) -> Vec<P<MetaItem>> { - // This is sort of stupid here, but we need to sort by - // human-readable strings. - let mut v = items.into_iter() - .map(|mi| (mi.name(), mi)) - .collect::<Vec<(InternedString, P<MetaItem>)>>(); - - v.sort_by(|&(ref a, _), &(ref b, _)| a.cmp(b)); - - // There doesn't seem to be a more optimal way to do this - v.into_iter().map(|(_, m)| m.map(|Spanned {node, span}| { - Spanned { - node: match node { - MetaItemKind::List(n, mis) => MetaItemKind::List(n, sort_meta_items(mis)), - _ => node - }, - span: span - } - })).collect() -} - pub fn find_crate_name(attrs: &[Attribute]) -> Option<InternedString> { first_attr_value_str_by_name(attrs, "crate_name") } @@ -427,14 +474,15 @@ pub fn find_inline_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> In if items.len() != 1 { diagnostic.map(|d|{ span_err!(d, attr.span, E0534, "expected one argument"); }); InlineAttr::None - } else if contains_name(&items[..], "always") { + } else if list_contains_name(&items[..], "always") { InlineAttr::Always - } else if contains_name(&items[..], "never") { + } else if list_contains_name(&items[..], "never") { InlineAttr::Never } else { diagnostic.map(|d| { - span_err!(d, (*items[0]).span, E0535, "invalid argument"); + span_err!(d, items[0].span, E0535, "invalid argument"); }); + InlineAttr::None } } @@ -453,27 +501,44 @@ pub fn requests_inline(attrs: &[Attribute]) -> bool { /// Tests if a cfg-pattern matches the cfg set pub fn cfg_matches(cfgs: &[P<MetaItem>], cfg: &ast::MetaItem, - sess: &ParseSess, features: Option<&Features>) + sess: &ParseSess, + features: Option<&Features>) -> bool { match cfg.node { - ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "any" => - mis.iter().any(|mi| cfg_matches(cfgs, &mi, sess, features)), - ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "all" => - mis.iter().all(|mi| cfg_matches(cfgs, &mi, sess, features)), - ast::MetaItemKind::List(ref pred, ref mis) if &pred[..] == "not" => { - if mis.len() != 1 { - span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern"); - return false; + ast::MetaItemKind::List(ref pred, ref mis) => { + for mi in mis.iter() { + if !mi.is_meta_item() { + handle_errors(&sess.span_diagnostic, mi.span, AttrError::UnsupportedLiteral); + return false; + } + } + + // The unwraps below may look dangerous, but we've already asserted + // that they won't fail with the loop above. + match &pred[..] { + "any" => mis.iter().any(|mi| { + cfg_matches(cfgs, mi.meta_item().unwrap(), sess, features) + }), + "all" => mis.iter().all(|mi| { + cfg_matches(cfgs, mi.meta_item().unwrap(), sess, features) + }), + "not" => { + if mis.len() != 1 { + span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern"); + return false; + } + + !cfg_matches(cfgs, mis[0].meta_item().unwrap(), sess, features) + }, + p => { + span_err!(sess.span_diagnostic, cfg.span, E0537, "invalid predicate `{}`", p); + false + } } - !cfg_matches(cfgs, &mis[0], sess, features) - } - ast::MetaItemKind::List(ref pred, _) => { - span_err!(sess.span_diagnostic, cfg.span, E0537, "invalid predicate `{}`", pred); - false }, ast::MetaItemKind::Word(_) | ast::MetaItemKind::NameValue(..) => { - if let (Some(features), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) { - gated_cfg.check_and_emit(sess, features); + if let (Some(feats), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) { + gated_cfg.check_and_emit(sess, feats); } contains(cfgs, cfg) } @@ -557,14 +622,19 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, let mut since = None; let mut reason = None; for meta in metas { - match &*meta.name() { - "since" => if !get(meta, &mut since) { continue 'outer }, - "reason" => if !get(meta, &mut reason) { continue 'outer }, - _ => { - handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(meta.name())); - continue 'outer + if let Some(mi) = meta.meta_item() { + match &*mi.name() { + "since" => if !get(mi, &mut since) { continue 'outer }, + "reason" => if !get(mi, &mut reason) { continue 'outer }, + _ => { + handle_errors(diagnostic, mi.span, + AttrError::UnknownMetaItem(mi.name())); + continue 'outer + } } + } else { + handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral); + continue 'outer } } @@ -595,15 +665,20 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, let mut reason = None; let mut issue = None; for meta in metas { - match &*meta.name() { - "feature" => if !get(meta, &mut feature) { continue 'outer }, - "reason" => if !get(meta, &mut reason) { continue 'outer }, - "issue" => if !get(meta, &mut issue) { continue 'outer }, - _ => { - handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(meta.name())); - continue 'outer + if let Some(mi) = meta.meta_item() { + match &*mi.name() { + "feature" => if !get(mi, &mut feature) { continue 'outer }, + "reason" => if !get(mi, &mut reason) { continue 'outer }, + "issue" => if !get(mi, &mut issue) { continue 'outer }, + _ => { + handle_errors(diagnostic, meta.span, + AttrError::UnknownMetaItem(mi.name())); + continue 'outer + } } + } else { + handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral); + continue 'outer } } @@ -645,14 +720,19 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, let mut feature = None; let mut since = None; for meta in metas { - match &*meta.name() { - "feature" => if !get(meta, &mut feature) { continue 'outer }, - "since" => if !get(meta, &mut since) { continue 'outer }, - _ => { - handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(meta.name())); - continue 'outer + if let NestedMetaItemKind::MetaItem(ref mi) = meta.node { + match &*mi.name() { + "feature" => if !get(mi, &mut feature) { continue 'outer }, + "since" => if !get(mi, &mut since) { continue 'outer }, + _ => { + handle_errors(diagnostic, meta.span, + AttrError::UnknownMetaItem(mi.name())); + continue 'outer + } } + } else { + handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral); + continue 'outer } } @@ -739,14 +819,19 @@ fn find_deprecation_generic<'a, I>(diagnostic: &Handler, let mut since = None; let mut note = None; for meta in metas { - match &*meta.name() { - "since" => if !get(meta, &mut since) { continue 'outer }, - "note" => if !get(meta, &mut note) { continue 'outer }, - _ => { - handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(meta.name())); - continue 'outer + if let NestedMetaItemKind::MetaItem(ref mi) = meta.node { + match &*mi.name() { + "since" => if !get(mi, &mut since) { continue 'outer }, + "note" => if !get(mi, &mut note) { continue 'outer }, + _ => { + handle_errors(diagnostic, meta.span, + AttrError::UnknownMetaItem(mi.name())); + continue 'outer + } } + } else { + handle_errors(diagnostic, meta.span, AttrError::UnsupportedLiteral); + continue 'outer } } @@ -796,32 +881,36 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr> ast::MetaItemKind::List(ref s, ref items) if s == "repr" => { mark_used(attr); for item in items { - match item.node { - ast::MetaItemKind::Word(ref word) => { - let hint = match &word[..] { - // Can't use "extern" because it's not a lexical identifier. - "C" => Some(ReprExtern), - "packed" => Some(ReprPacked), - "simd" => Some(ReprSimd), - _ => match int_type_of_word(&word) { - Some(ity) => Some(ReprInt(item.span, ity)), - None => { - // Not a word we recognize - span_err!(diagnostic, item.span, E0552, - "unrecognized representation hint"); - None - } - } - }; + if !item.is_meta_item() { + handle_errors(diagnostic, item.span, AttrError::UnsupportedLiteral); + continue + } - match hint { - Some(h) => acc.push(h), - None => { } + if let Some(mi) = item.word() { + let word = &*mi.name(); + let hint = match word { + // Can't use "extern" because it's not a lexical identifier. + "C" => Some(ReprExtern), + "packed" => Some(ReprPacked), + "simd" => Some(ReprSimd), + _ => match int_type_of_word(word) { + Some(ity) => Some(ReprInt(item.span, ity)), + None => { + // Not a word we recognize + span_err!(diagnostic, item.span, E0552, + "unrecognized representation hint"); + None + } } + }; + + match hint { + Some(h) => acc.push(h), + None => { } } - // Not a word: - _ => span_err!(diagnostic, item.span, E0553, - "unrecognized enum representation hint"), + } else { + span_err!(diagnostic, item.span, E0553, + "unrecognized enum representation hint"); } } } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index a825cf866a8..69a97917652 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use attr::{AttrMetaMethods, HasAttrs}; +use attr::HasAttrs; use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue}; use fold::Folder; use {fold, attr}; @@ -52,6 +52,7 @@ impl<'a> StripUnconfigured<'a> { return None; } }; + let (cfg, mi) = match (attr_list.len(), attr_list.get(0), attr_list.get(1)) { (2, Some(cfg), Some(mi)) => (cfg, mi), _ => { @@ -61,15 +62,24 @@ impl<'a> StripUnconfigured<'a> { } }; - if attr::cfg_matches(self.config, &cfg, self.sess, self.features) { - self.process_cfg_attr(respan(mi.span, ast::Attribute_ { - id: attr::mk_attr_id(), - style: attr.node.style, - value: mi.clone(), - is_sugared_doc: false, - })) - } else { - None + use attr::cfg_matches; + match (cfg.meta_item(), mi.meta_item()) { + (Some(cfg), Some(mi)) => + if cfg_matches(self.config, &cfg, self.sess, self.features) { + self.process_cfg_attr(respan(mi.span, ast::Attribute_ { + id: attr::mk_attr_id(), + style: attr.node.style, + value: mi.clone(), + is_sugared_doc: false, + })) + } else { + None + }, + _ => { + let msg = "unexpected literal(s) in `#[cfg_attr(<cfg pattern>, <attr>)]`"; + self.sess.span_diagnostic.span_err(attr.span, msg); + None + } } } @@ -91,7 +101,12 @@ impl<'a> StripUnconfigured<'a> { return true; } - attr::cfg_matches(self.config, &mis[0], self.sess, self.features) + if !mis[0].is_meta_item() { + self.sess.span_diagnostic.span_err(mis[0].span, "unexpected literal"); + return true; + } + + attr::cfg_matches(self.config, mis[0].meta_item().unwrap(), self.sess, self.features) }) } @@ -165,6 +180,9 @@ impl<'a> fold::Folder for StripUnconfigured<'a> { ast::ItemKind::Struct(def, generics) => { ast::ItemKind::Struct(fold_struct(self, def), generics) } + ast::ItemKind::Union(def, generics) => { + ast::ItemKind::Union(fold_struct(self, def), generics) + } ast::ItemKind::Enum(def, generics) => { let variants = def.variants.into_iter().filter_map(|v| { self.configure(v).map(|v| { diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 010b1d638e6..9110e989a8a 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -161,6 +161,24 @@ fn main() {} ``` "##, +E0565: r##" +A literal was used in an attribute that doesn't support literals. + +Erroneous code example: + +```compile_fail,E0565 +#[inline("always")] // error: unsupported literal +pub fn something() {} +``` + +Literals in attributes are new and largely unsupported. Work to support literals +where appropriate is ongoing. Try using an unquoted name instead: + +``` +#[inline(always)] +pub fn something() {} +``` +"##, } register_diagnostics! { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 6ba3b92483f..43e190f5deb 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -60,13 +60,6 @@ impl HasAttrs for Annotatable { } impl Annotatable { - pub fn attrs(&self) -> &[ast::Attribute] { - HasAttrs::attrs(self) - } - pub fn fold_attrs(self, attrs: Vec<ast::Attribute>) -> Annotatable { - self.map_attrs(|_| attrs) - } - pub fn expect_item(self) -> P<ast::Item> { match self { Annotatable::Item(i) => i, diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 5d6429f7bdf..3dcdbc89096 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -12,7 +12,7 @@ use abi::Abi; use ast::{self, Ident, Generics, Expr, BlockCheckMode, UnOp, PatKind}; use attr; use syntax_pos::{Span, DUMMY_SP, Pos}; -use codemap::{respan, Spanned}; +use codemap::{dummy_spanned, respan, Spanned}; use ext::base::ExtCtxt; use parse::token::{self, keywords, InternedString}; use ptr::P; @@ -171,9 +171,11 @@ pub trait AstBuilder { span: Span, ident: ast::Ident, bm: ast::BindingMode) -> P<ast::Pat>; - fn pat_enum(&self, span: Span, path: ast::Path, subpats: Vec<P<ast::Pat>> ) -> P<ast::Pat>; - fn pat_struct(&self, span: Span, - path: ast::Path, field_pats: Vec<Spanned<ast::FieldPat>> ) -> P<ast::Pat>; + fn pat_path(&self, span: Span, path: ast::Path) -> P<ast::Pat>; + fn pat_tuple_struct(&self, span: Span, path: ast::Path, + subpats: Vec<P<ast::Pat>>) -> P<ast::Pat>; + fn pat_struct(&self, span: Span, path: ast::Path, + field_pats: Vec<Spanned<ast::FieldPat>>) -> P<ast::Pat>; fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat>; fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat>; @@ -277,10 +279,13 @@ pub trait AstBuilder { fn attribute(&self, sp: Span, mi: P<ast::MetaItem>) -> ast::Attribute; fn meta_word(&self, sp: Span, w: InternedString) -> P<ast::MetaItem>; + + fn meta_list_item_word(&self, sp: Span, w: InternedString) -> ast::NestedMetaItem; + fn meta_list(&self, sp: Span, name: InternedString, - mis: Vec<P<ast::MetaItem>> ) + mis: Vec<ast::NestedMetaItem> ) -> P<ast::MetaItem>; fn meta_name_value(&self, sp: Span, @@ -802,10 +807,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let binding_expr = self.expr_ident(sp, binding_variable); // Ok(__try_var) pattern - let ok_pat = self.pat_enum(sp, ok_path, vec!(binding_pat.clone())); + let ok_pat = self.pat_tuple_struct(sp, ok_path, vec![binding_pat.clone()]); // Err(__try_var) (pattern and expression resp.) - let err_pat = self.pat_enum(sp, err_path.clone(), vec!(binding_pat)); + let err_pat = self.pat_tuple_struct(sp, err_path.clone(), vec![binding_pat]); let err_inner_expr = self.expr_call(sp, self.expr_path(err_path), vec!(binding_expr.clone())); // return Err(__try_var) @@ -842,18 +847,16 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let pat = PatKind::Ident(bm, Spanned{span: span, node: ident}, None); self.pat(span, pat) } - fn pat_enum(&self, span: Span, path: ast::Path, subpats: Vec<P<ast::Pat>>) -> P<ast::Pat> { - let pat = if subpats.is_empty() { - PatKind::Path(None, path) - } else { - PatKind::TupleStruct(path, subpats, None) - }; - self.pat(span, pat) + fn pat_path(&self, span: Span, path: ast::Path) -> P<ast::Pat> { + self.pat(span, PatKind::Path(None, path)) } - fn pat_struct(&self, span: Span, - path: ast::Path, field_pats: Vec<Spanned<ast::FieldPat>>) -> P<ast::Pat> { - let pat = PatKind::Struct(path, field_pats, false); - self.pat(span, pat) + fn pat_tuple_struct(&self, span: Span, path: ast::Path, + subpats: Vec<P<ast::Pat>>) -> P<ast::Pat> { + self.pat(span, PatKind::TupleStruct(path, subpats, None)) + } + fn pat_struct(&self, span: Span, path: ast::Path, + field_pats: Vec<Spanned<ast::FieldPat>>) -> P<ast::Pat> { + self.pat(span, PatKind::Struct(path, field_pats, false)) } fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat> { self.pat(span, PatKind::Tuple(pats, None)) @@ -862,25 +865,25 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> { let some = self.std_path(&["option", "Option", "Some"]); let path = self.path_global(span, some); - self.pat_enum(span, path, vec!(pat)) + self.pat_tuple_struct(span, path, vec![pat]) } fn pat_none(&self, span: Span) -> P<ast::Pat> { let some = self.std_path(&["option", "Option", "None"]); let path = self.path_global(span, some); - self.pat_enum(span, path, vec!()) + self.pat_path(span, path) } fn pat_ok(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> { let some = self.std_path(&["result", "Result", "Ok"]); let path = self.path_global(span, some); - self.pat_enum(span, path, vec!(pat)) + self.pat_tuple_struct(span, path, vec![pat]) } fn pat_err(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> { let some = self.std_path(&["result", "Result", "Err"]); let path = self.path_global(span, some); - self.pat_enum(span, path, vec!(pat)) + self.pat_tuple_struct(span, path, vec![pat]) } fn arm(&self, _span: Span, pats: Vec<P<ast::Pat>>, expr: P<ast::Expr>) -> ast::Arm { @@ -1016,7 +1019,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { Vec::new(), ast::ItemKind::Fn(self.fn_decl(inputs, output), ast::Unsafety::Normal, - ast::Constness::NotConst, + dummy_spanned(ast::Constness::NotConst), Abi::Rust, generics, body)) @@ -1141,10 +1144,16 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn meta_word(&self, sp: Span, w: InternedString) -> P<ast::MetaItem> { attr::mk_spanned_word_item(sp, w) } - fn meta_list(&self, sp: Span, name: InternedString, mis: Vec<P<ast::MetaItem>>) + + fn meta_list_item_word(&self, sp: Span, w: InternedString) -> ast::NestedMetaItem { + respan(sp, ast::NestedMetaItemKind::MetaItem(attr::mk_spanned_word_item(sp, w))) + } + + fn meta_list(&self, sp: Span, name: InternedString, mis: Vec<ast::NestedMetaItem>) -> P<ast::MetaItem> { attr::mk_spanned_list_item(sp, name, mis) } + fn meta_name_value(&self, sp: Span, name: InternedString, value: ast::LitKind) -> P<ast::MetaItem> { attr::mk_spanned_name_value_item(sp, name, respan(sp, value)) @@ -1178,7 +1187,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn item_use_list(&self, sp: Span, vis: ast::Visibility, path: Vec<ast::Ident>, imports: &[ast::Ident]) -> P<ast::Item> { let imports = imports.iter().map(|id| { - let item = ast::PathListItemKind::Ident { + let item = ast::PathListItem_ { name: *id, rename: None, id: ast::DUMMY_NODE_ID, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 26599208ec0..15ebf95d623 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -13,7 +13,6 @@ use ast::{MacStmtStyle, Stmt, StmtKind, ItemKind}; use ast; use ext::hygiene::Mark; use attr::{self, HasAttrs}; -use attr::AttrMetaMethods; use codemap::{dummy_spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; use syntax_pos::{self, Span, ExpnId}; use config::StripUnconfigured; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index dc68e064634..1e15c156356 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -26,11 +26,9 @@ use self::AttributeType::*; use self::AttributeGate::*; use abi::Abi; -use ast::{NodeId, PatKind}; -use ast; +use ast::{self, NodeId, PatKind}; use attr; -use attr::AttrMetaMethods; -use codemap::CodeMap; +use codemap::{CodeMap, Spanned}; use syntax_pos::Span; use errors::Handler; use visit::{self, FnKind, Visitor}; @@ -280,7 +278,10 @@ declare_features! ( (active, relaxed_adts, "1.12.0", Some(35626)), // The `!` type - (active, never_type, "1.13.0", Some(35121)) + (active, never_type, "1.13.0", Some(35121)), + + // Allows all literals in attribute lists and values of key-value pairs. + (active, attr_literals, "1.13.0", Some(34981)) ); declare_features! ( @@ -830,11 +831,34 @@ impl<'a> PostExpansionVisitor<'a> { } } +fn contains_novel_literal(item: &ast::MetaItem) -> bool { + use ast::MetaItemKind::*; + use ast::NestedMetaItemKind::*; + + match item.node { + Word(..) => false, + NameValue(_, ref lit) => !lit.node.is_str(), + List(_, ref list) => list.iter().any(|li| { + match li.node { + MetaItem(ref mi) => contains_novel_literal(&**mi), + Literal(_) => true, + } + }), + } +} + impl<'a> Visitor for PostExpansionVisitor<'a> { fn visit_attribute(&mut self, attr: &ast::Attribute) { if !self.context.cm.span_allows_unstable(attr.span) { + // check for gated attributes self.context.check_attribute(attr, false); } + + if contains_novel_literal(&*(attr.node.value)) { + gate_feature_post!(&self, attr_literals, attr.span, + "non-string literals in attributes, or string \ + literals in top-level positions, are experimental"); + } } fn visit_name(&mut self, sp: Span, name: ast::Name) { @@ -894,7 +918,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { for attr in &i.attrs { if attr.name() == "repr" { for item in attr.meta_item_list().unwrap_or(&[]) { - if item.name() == "simd" { + if item.check_name("simd") { gate_feature_post!(&self, repr_simd, i.span, "SIMD types are experimental \ and possibly buggy"); @@ -1046,7 +1070,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { _node_id: NodeId) { // check for const fn declarations match fn_kind { - FnKind::ItemFn(_, _, _, ast::Constness::Const, _, _) => { + FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _) => { gate_feature_post!(&self, const_fn, span, "const fn is unstable"); } _ => { @@ -1078,7 +1102,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { if block.is_none() { self.check_abi(sig.abi, ti.span); } - if sig.constness == ast::Constness::Const { + if sig.constness.node == ast::Constness::Const { gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable"); } } @@ -1105,7 +1129,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { "associated constants are experimental") } ast::ImplItemKind::Method(ref sig, _) => { - if sig.constness == ast::Constness::Const { + if sig.constness.node == ast::Constness::Const { gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable"); } } @@ -1154,13 +1178,14 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> F } Some(list) => { for mi in list { - let name = if mi.is_word() { - mi.name() - } else { - span_err!(span_handler, mi.span, E0556, - "malformed feature, expected just one word"); - continue - }; + 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 + }; + if let Some(&(_, _, _, setter)) = ACTIVE_FEATURES.iter() .find(|& &(n, _, _, _)| name == n) { *(setter(&mut features)) = true; diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index b257ab98987..7500bfe9caa 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -47,6 +47,10 @@ pub trait Folder : Sized { noop_fold_meta_items(meta_items, self) } + fn fold_meta_list_item(&mut self, list_item: NestedMetaItem) -> NestedMetaItem { + noop_fold_meta_list_item(list_item, self) + } + fn fold_meta_item(&mut self, meta_item: P<MetaItem>) -> P<MetaItem> { noop_fold_meta_item(meta_item, self) } @@ -307,18 +311,10 @@ pub fn noop_fold_view_path<T: Folder>(view_path: P<ViewPath>, fld: &mut T) -> P< ViewPathList(fld.fold_path(path), path_list_idents.move_map(|path_list_ident| { Spanned { - node: match path_list_ident.node { - PathListItemKind::Ident { id, name, rename } => - PathListItemKind::Ident { - id: fld.new_id(id), - rename: rename, - name: name - }, - PathListItemKind::Mod { id, rename } => - PathListItemKind::Mod { - id: fld.new_id(id), - rename: rename - } + node: PathListItem_ { + id: fld.new_id(path_list_ident.node.id), + rename: path_list_ident.node.rename, + name: path_list_ident.node.name, }, span: fld.new_span(path_list_ident.span) } @@ -513,12 +509,25 @@ pub fn noop_fold_mac<T: Folder>(Spanned {node, span}: Mac, fld: &mut T) -> Mac { } } +pub fn noop_fold_meta_list_item<T: Folder>(li: NestedMetaItem, fld: &mut T) + -> NestedMetaItem { + Spanned { + node: match li.node { + NestedMetaItemKind::MetaItem(mi) => { + NestedMetaItemKind::MetaItem(fld.fold_meta_item(mi)) + }, + NestedMetaItemKind::Literal(lit) => NestedMetaItemKind::Literal(lit) + }, + span: fld.new_span(li.span) + } +} + pub fn noop_fold_meta_item<T: Folder>(mi: P<MetaItem>, fld: &mut T) -> P<MetaItem> { mi.map(|Spanned {node, span}| Spanned { node: match node { MetaItemKind::Word(id) => MetaItemKind::Word(id), MetaItemKind::List(id, mis) => { - MetaItemKind::List(id, mis.move_map(|e| fld.fold_meta_item(e))) + MetaItemKind::List(id, mis.move_map(|e| fld.fold_meta_list_item(e))) } MetaItemKind::NameValue(id, s) => MetaItemKind::NameValue(id, s) }, @@ -698,12 +707,13 @@ pub fn noop_fold_opt_lifetime<T: Folder>(o_lt: Option<Lifetime>, fld: &mut T) o_lt.map(|lt| fld.fold_lifetime(lt)) } -pub fn noop_fold_generics<T: Folder>(Generics {ty_params, lifetimes, where_clause}: Generics, +pub fn noop_fold_generics<T: Folder>(Generics {ty_params, lifetimes, where_clause, span}: Generics, fld: &mut T) -> Generics { Generics { ty_params: fld.fold_ty_params(ty_params), lifetimes: fld.fold_lifetime_defs(lifetimes), where_clause: fld.fold_where_clause(where_clause), + span: fld.new_span(span), } } @@ -875,6 +885,10 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind { let struct_def = folder.fold_variant_data(struct_def); ItemKind::Struct(struct_def, folder.fold_generics(generics)) } + ItemKind::Union(struct_def, generics) => { + let struct_def = folder.fold_variant_data(struct_def); + ItemKind::Union(struct_def, folder.fold_generics(generics)) + } ItemKind::DefaultImpl(unsafety, ref trait_ref) => { ItemKind::DefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone())) } diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 2ae3236cd5a..27dd055cd3a 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -193,9 +193,26 @@ impl<'a> Parser<'a> { Ok(attrs) } - /// matches meta_item = IDENT - /// | IDENT = lit - /// | IDENT meta_seq + fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> { + let lit = self.parse_lit()?; + debug!("Checking if {:?} is unusuffixed.", lit); + + if !lit.node.is_unsuffixed() { + let msg = "suffixed literals are not allowed in attributes"; + self.diagnostic().struct_span_err(lit.span, msg) + .help("instead of using a suffixed literal \ + (1u8, 1.0f32, etc.), use an unsuffixed version \ + (1, 1.0, etc.).") + .emit() + } + + Ok(lit) + } + + /// Per RFC#1559, matches the following grammar: + /// + /// meta_item : IDENT ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ; + /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; pub fn parse_meta_item(&mut self) -> PResult<'a, P<ast::MetaItem>> { let nt_meta = match self.token { token::Interpolated(token::NtMeta(ref e)) => Some(e.clone()), @@ -213,16 +230,7 @@ impl<'a> Parser<'a> { match self.token { token::Eq => { self.bump(); - let lit = self.parse_lit()?; - // FIXME #623 Non-string meta items are not serialized correctly; - // just forbid them for now - match lit.node { - ast::LitKind::Str(..) => {} - _ => { - self.span_err(lit.span, - "non-string literals are not allowed in meta-items"); - } - } + let lit = self.parse_unsuffixed_lit()?; let hi = self.span.hi; Ok(P(spanned(lo, hi, ast::MetaItemKind::NameValue(name, lit)))) } @@ -238,11 +246,35 @@ impl<'a> Parser<'a> { } } - /// matches meta_seq = ( COMMASEP(meta_item) ) - fn parse_meta_seq(&mut self) -> PResult<'a, Vec<P<ast::MetaItem>>> { + /// matches meta_item_inner : (meta_item | UNSUFFIXED_LIT) ; + fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { + let sp = self.span; + let lo = self.span.lo; + + match self.parse_unsuffixed_lit() { + Ok(lit) => { + return Ok(spanned(lo, self.span.hi, ast::NestedMetaItemKind::Literal(lit))) + } + Err(ref mut err) => self.diagnostic().cancel(err) + } + + match self.parse_meta_item() { + Ok(mi) => { + return Ok(spanned(lo, self.span.hi, ast::NestedMetaItemKind::MetaItem(mi))) + } + Err(ref mut err) => self.diagnostic().cancel(err) + } + + let found = self.this_token_to_string(); + let msg = format!("expected unsuffixed literal or identifier, found {}", found); + Err(self.diagnostic().struct_span_err(sp, &msg)) + } + + /// matches meta_seq = ( COMMASEP(meta_item_inner) ) + fn parse_meta_seq(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> { self.parse_unspanned_seq(&token::OpenDelim(token::Paren), &token::CloseDelim(token::Paren), SeqSep::trailing_allowed(token::Comma), - |p: &mut Parser<'a>| p.parse_meta_item()) + |p: &mut Parser<'a>| p.parse_meta_item_inner()) } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index cd1fdcfe9d1..af95e44a567 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -674,11 +674,11 @@ pub fn integer_lit(s: &str, mod tests { use super::*; use std::rc::Rc; - use syntax_pos::{Span, BytePos, Pos, NO_EXPANSION}; + use syntax_pos::{self, Span, BytePos, Pos, NO_EXPANSION}; use codemap::Spanned; use ast::{self, PatKind}; use abi::Abi; - use attr::{first_attr_value_str_by_name, AttrMetaMethods}; + use attr::first_attr_value_str_by_name; use parse; use parse::parser::Parser; use parse::token::{str_to_ident}; @@ -937,7 +937,10 @@ mod tests { variadic: false }), ast::Unsafety::Normal, - ast::Constness::NotConst, + Spanned { + span: sp(0,2), + node: ast::Constness::NotConst, + }, Abi::Rust, ast::Generics{ // no idea on either of these: lifetimes: Vec::new(), @@ -945,7 +948,8 @@ mod tests { where_clause: ast::WhereClause { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), - } + }, + span: syntax_pos::DUMMY_SP, }, P(ast::Block { stmts: vec!(ast::Stmt { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 1646246069e..92ec0fdb3de 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -39,7 +39,7 @@ use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; use ast::{Visibility, WhereClause}; use ast::{BinOpKind, UnOp}; use ast; -use codemap::{self, CodeMap, Spanned, spanned}; +use codemap::{self, CodeMap, Spanned, spanned, respan}; use syntax_pos::{self, Span, BytePos, mk_sp}; use errors::{self, DiagnosticBuilder}; use ext::tt::macro_parser; @@ -725,8 +725,8 @@ impl<'a> Parser<'a> { let gt_str = Parser::token_to_string(&token::Gt); let this_token_str = self.this_token_to_string(); Err(self.fatal(&format!("expected `{}`, found `{}`", - gt_str, - this_token_str))) + gt_str, + this_token_str))) } } } @@ -4293,6 +4293,7 @@ impl<'a> Parser<'a> { /// where typaramseq = ( typaram ) | ( typaram , typaramseq ) pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> { maybe_whole!(self, NtGenerics); + let span_lo = self.span.lo; if self.eat(&token::Lt) { let lifetime_defs = self.parse_lifetime_defs()?; @@ -4315,7 +4316,8 @@ impl<'a> Parser<'a> { where_clause: WhereClause { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), - } + }, + span: mk_sp(span_lo, self.last_span.hi), }) } else { Ok(ast::Generics::default()) @@ -4768,7 +4770,7 @@ impl<'a> Parser<'a> { /// Parse an item-position function declaration. fn parse_item_fn(&mut self, unsafety: Unsafety, - constness: Constness, + constness: Spanned<Constness>, abi: abi::Abi) -> PResult<'a, ItemInfo> { let (ident, mut generics) = self.parse_fn_header()?; @@ -4794,18 +4796,21 @@ impl<'a> Parser<'a> { /// - `extern fn` /// - etc pub fn parse_fn_front_matter(&mut self) - -> PResult<'a, (ast::Constness, ast::Unsafety, abi::Abi)> { + -> PResult<'a, (Spanned<ast::Constness>, + ast::Unsafety, + abi::Abi)> { let is_const_fn = self.eat_keyword(keywords::Const); + let const_span = self.last_span; let unsafety = self.parse_unsafety()?; let (constness, unsafety, abi) = if is_const_fn { - (Constness::Const, unsafety, Abi::Rust) + (respan(const_span, Constness::Const), unsafety, Abi::Rust) } else { let abi = if self.eat_keyword(keywords::Extern) { self.parse_opt_abi()?.unwrap_or(Abi::C) } else { Abi::Rust }; - (Constness::NotConst, unsafety, abi) + (respan(self.last_span, Constness::NotConst), unsafety, abi) }; self.expect_keyword(keywords::Fn)?; Ok((constness, unsafety, abi)) @@ -5704,9 +5709,12 @@ impl<'a> Parser<'a> { if self.eat_keyword(keywords::Fn) { // EXTERN FUNCTION ITEM + let fn_span = self.last_span; let abi = opt_abi.unwrap_or(Abi::C); let (ident, item_, extra_attrs) = - self.parse_item_fn(Unsafety::Normal, Constness::NotConst, abi)?; + self.parse_item_fn(Unsafety::Normal, + respan(fn_span, Constness::NotConst), + abi)?; let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5740,6 +5748,7 @@ impl<'a> Parser<'a> { return Ok(Some(item)); } if self.eat_keyword(keywords::Const) { + let const_span = self.last_span; if self.check_keyword(keywords::Fn) || (self.check_keyword(keywords::Unsafe) && self.look_ahead(1, |t| t.is_keyword(keywords::Fn))) { @@ -5751,7 +5760,9 @@ impl<'a> Parser<'a> { }; self.bump(); let (ident, item_, extra_attrs) = - self.parse_item_fn(unsafety, Constness::Const, Abi::Rust)?; + self.parse_item_fn(unsafety, + respan(const_span, Constness::Const), + Abi::Rust)?; let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5815,8 +5826,11 @@ impl<'a> Parser<'a> { if self.check_keyword(keywords::Fn) { // FUNCTION ITEM self.bump(); + let fn_span = self.last_span; let (ident, item_, extra_attrs) = - self.parse_item_fn(Unsafety::Normal, Constness::NotConst, Abi::Rust)?; + self.parse_item_fn(Unsafety::Normal, + respan(fn_span, Constness::NotConst), + Abi::Rust)?; let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5836,8 +5850,11 @@ impl<'a> Parser<'a> { Abi::Rust }; self.expect_keyword(keywords::Fn)?; + let fn_span = self.last_span; let (ident, item_, extra_attrs) = - self.parse_item_fn(Unsafety::Unsafe, Constness::NotConst, abi)?; + self.parse_item_fn(Unsafety::Unsafe, + respan(fn_span, Constness::NotConst), + abi)?; let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -6038,13 +6055,16 @@ impl<'a> Parser<'a> { &token::CloseDelim(token::Brace), SeqSep::trailing_allowed(token::Comma), |this| { let lo = this.span.lo; - let node = if this.eat_keyword(keywords::SelfValue) { - let rename = this.parse_rename()?; - ast::PathListItemKind::Mod { id: ast::DUMMY_NODE_ID, rename: rename } + let ident = if this.eat_keyword(keywords::SelfValue) { + keywords::SelfValue.ident() } else { - let ident = this.parse_ident()?; - let rename = this.parse_rename()?; - ast::PathListItemKind::Ident { name: ident, rename: rename, id: ast::DUMMY_NODE_ID } + this.parse_ident()? + }; + let rename = this.parse_rename()?; + let node = ast::PathListItem_ { + name: ident, + rename: rename, + id: ast::DUMMY_NODE_ID }; let hi = this.last_span.hi; Ok(spanned(lo, hi, node)) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index a77c678248b..8563d27908d 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -16,7 +16,6 @@ use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::Attribute; use util::parser::AssocOp; use attr; -use attr::{AttrMetaMethods, AttributeMethods}; use codemap::{self, CodeMap}; use syntax_pos::{self, BytePos}; use errors; @@ -120,7 +119,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap, // of the feature gate, so we fake them up here. // #![feature(prelude_import)] - let prelude_import_meta = attr::mk_word_item(InternedString::new("prelude_import")); + let prelude_import_meta = attr::mk_list_word_item(InternedString::new("prelude_import")); let list = attr::mk_list_item(InternedString::new("feature"), vec![prelude_import_meta]); let fake_attr = attr::mk_attr_inner(attr::mk_attr_id(), list); @@ -406,6 +405,10 @@ pub fn block_to_string(blk: &ast::Block) -> String { }) } +pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String { + to_string(|s| s.print_meta_list_item(li)) +} + pub fn meta_item_to_string(mi: &ast::MetaItem) -> String { to_string(|s| s.print_meta_item(mi)) } @@ -764,6 +767,17 @@ pub trait PrintState<'a> { } } + fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) -> io::Result<()> { + match item.node { + ast::NestedMetaItemKind::MetaItem(ref mi) => { + self.print_meta_item(mi) + }, + ast::NestedMetaItemKind::Literal(ref lit) => { + self.print_literal(lit) + } + } + } + fn print_meta_item(&mut self, item: &ast::MetaItem) -> io::Result<()> { try!(self.ibox(INDENT_UNIT)); match item.node { @@ -780,7 +794,7 @@ pub trait PrintState<'a> { try!(self.popen()); try!(self.commasep(Consistent, &items[..], - |s, i| s.print_meta_item(&i))); + |s, i| s.print_meta_list_item(&i))); try!(self.pclose()); } } @@ -1001,6 +1015,7 @@ impl<'a> State<'a> { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), }, + span: syntax_pos::DUMMY_SP, }; try!(self.print_ty_fn(f.abi, f.unsafety, @@ -1184,7 +1199,7 @@ impl<'a> State<'a> { try!(self.print_fn( decl, unsafety, - constness, + constness.node, abi, Some(item.ident), typarams, @@ -1236,7 +1251,10 @@ impl<'a> State<'a> { try!(self.head(&visibility_qualified(&item.vis, "struct"))); try!(self.print_struct(&struct_def, generics, item.ident, item.span, true)); } - + ast::ItemKind::Union(ref struct_def, ref generics) => { + try!(self.head(&visibility_qualified(&item.vis, "union"))); + try!(self.print_struct(&struct_def, generics, item.ident, item.span, true)); + } ast::ItemKind::DefaultImpl(unsafety, ref trait_ref) => { try!(self.head("")); try!(self.print_visibility(&item.vis)); @@ -1518,7 +1536,7 @@ impl<'a> State<'a> { -> io::Result<()> { self.print_fn(&m.decl, m.unsafety, - m.constness, + m.constness.node, m.abi, Some(ident), &m.generics, @@ -2878,26 +2896,13 @@ impl<'a> State<'a> { try!(word(&mut self.s, "::{")); } try!(self.commasep(Inconsistent, &idents[..], |s, w| { - match w.node { - ast::PathListItemKind::Ident { name, rename, .. } => { - try!(s.print_ident(name)); - if let Some(ident) = rename { - try!(space(&mut s.s)); - try!(s.word_space("as")); - try!(s.print_ident(ident)); - } - Ok(()) - }, - ast::PathListItemKind::Mod { rename, .. } => { - try!(word(&mut s.s, "self")); - if let Some(ident) = rename { - try!(space(&mut s.s)); - try!(s.word_space("as")); - try!(s.print_ident(ident)); - } - Ok(()) - } + try!(s.print_ident(w.node.name)); + if let Some(ident) = w.node.rename { + try!(space(&mut s.s)); + try!(s.word_space("as")); + try!(s.print_ident(ident)); } + Ok(()) })); word(&mut self.s, "}") } @@ -2982,6 +2987,7 @@ impl<'a> State<'a> { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), }, + span: syntax_pos::DUMMY_SP, }; try!(self.print_fn(decl, unsafety, diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index faf6a17a150..6155ad729a2 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -19,12 +19,11 @@ use std::iter; use std::slice; use std::mem; use std::vec; -use attr::AttrMetaMethods; use attr; use syntax_pos::{self, DUMMY_SP, NO_EXPANSION, Span, FileMap, BytePos}; use std::rc::Rc; -use codemap::{self, CodeMap, ExpnInfo, NameAndSpan, MacroAttribute}; +use codemap::{self, CodeMap, ExpnInfo, NameAndSpan, MacroAttribute, dummy_spanned}; use errors; use errors::snippet::{SnippetData}; use config; @@ -210,9 +209,8 @@ impl fold::Folder for EntryPointCleaner { folded.map(|ast::Item {id, ident, attrs, node, vis, span}| { let allow_str = InternedString::new("allow"); let dead_code_str = InternedString::new("dead_code"); - let allow_dead_code_item = - attr::mk_list_item(allow_str, - vec![attr::mk_word_item(dead_code_str)]); + let word_vec = vec![attr::mk_list_word_item(dead_code_str)]; + let allow_dead_code_item = attr::mk_list_item(allow_str, word_vec); let allow_dead_code = attr::mk_attr_outer(attr::mk_attr_id(), allow_dead_code_item); @@ -413,6 +411,7 @@ fn should_panic(i: &ast::Item) -> ShouldPanic { Some(attr) => { let msg = attr.meta_item_list() .and_then(|list| list.iter().find(|mi| mi.check_name("expected"))) + .and_then(|li| li.meta_item()) .and_then(|mi| mi.value_str()); ShouldPanic::Yes(msg) } @@ -485,7 +484,7 @@ fn mk_main(cx: &mut TestCtxt) -> P<ast::Item> { let main_body = ecx.block(sp, vec![call_test_main]); let main = ast::ItemKind::Fn(ecx.fn_decl(vec![], main_ret_ty), ast::Unsafety::Normal, - ast::Constness::NotConst, + dummy_spanned(ast::Constness::NotConst), ::abi::Abi::Rust, ast::Generics::default(), main_body); let main = P(ast::Item { ident: token::str_to_ident("main"), diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 582412119ca..efd9b027504 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -31,7 +31,7 @@ use codemap::Spanned; #[derive(Copy, Clone, PartialEq, Eq)] pub enum FnKind<'a> { /// fn foo() or extern "Abi" fn foo() - ItemFn(Ident, &'a Generics, Unsafety, Constness, Abi, &'a Visibility), + ItemFn(Ident, &'a Generics, Unsafety, Spanned<Constness>, Abi, &'a Visibility), /// fn foo(&self) Method(Ident, &'a MethodSig, Option<&'a Visibility>), @@ -278,7 +278,8 @@ pub fn walk_item<V: Visitor>(visitor: &mut V, item: &Item) { visitor.visit_ty(typ); walk_list!(visitor, visit_impl_item, impl_items); } - ItemKind::Struct(ref struct_definition, ref generics) => { + ItemKind::Struct(ref struct_definition, ref generics) | + ItemKind::Union(ref struct_definition, ref generics) => { visitor.visit_generics(generics); visitor.visit_variant_data(struct_definition, item.ident, generics, item.id, item.span); @@ -367,8 +368,8 @@ pub fn walk_path<V: Visitor>(visitor: &mut V, path: &Path) { } pub fn walk_path_list_item<V: Visitor>(visitor: &mut V, _prefix: &Path, item: &PathListItem) { - walk_opt_ident(visitor, item.span, item.node.name()); - walk_opt_ident(visitor, item.span, item.node.rename()); + visitor.visit_ident(item.span, item.node.name); + walk_opt_ident(visitor, item.span, item.node.rename); } pub fn walk_path_segment<V: Visitor>(visitor: &mut V, path_span: Span, segment: &PathSegment) { |
