From 759bd01e039452a1a357d347aea51348f9ffc443 Mon Sep 17 00:00:00 2001 From: Seiichi Uchida Date: Tue, 30 Jan 2018 14:30:39 +0900 Subject: [PATCH] Allow Path for name of MetaItem --- src/librustc/ich/impls_syntax.rs | 16 +++- src/librustc_driver/lib.rs | 2 +- src/librustc_resolve/macros.rs | 2 +- src/libsyntax/ast.rs | 4 +- src/libsyntax/attr.rs | 139 ++++++++++++++++++++++--------- src/libsyntax/ext/derive.rs | 3 +- src/libsyntax/ext/expand.rs | 2 +- src/libsyntax/parse/attr.rs | 7 +- src/libsyntax/print/pprust.rs | 36 ++++---- 9 files changed, 141 insertions(+), 70 deletions(-) diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index c1e86473996d0..ed7b79b392d89 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -211,6 +211,17 @@ impl<'a> HashStable> for [ast::Attribute] { } } +impl<'a> HashStable> for ast::Path { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + self.segments.len().hash_stable(hcx, hasher); + for segment in &self.segments { + segment.identifier.name.hash_stable(hcx, hasher); + } + } +} + impl<'a> HashStable> for ast::Attribute { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, @@ -229,10 +240,7 @@ impl<'a> HashStable> for ast::Attribute { } = *self; style.hash_stable(hcx, hasher); - path.segments.len().hash_stable(hcx, hasher); - for segment in &path.segments { - segment.ident.name.hash_stable(hcx, hasher); - } + path.hash_stable(hcx, hasher); for tt in tokens.trees() { tt.hash_stable(hcx, hasher); } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 3f166daac717e..67ba55a6aabd2 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1060,7 +1060,7 @@ impl RustcDefaultCalls { let mut cfgs = Vec::new(); for &(name, ref value) in sess.parse_sess.config.iter() { let gated_cfg = GatedCfg::gate(&ast::MetaItem { - ident: ast::Ident::with_empty_ctxt(name), + name: ast::Path::from_ident(DUMMY_SP, name.to_ident()), node: ast::MetaItemKind::Word, span: DUMMY_SP, }); diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 3d20f922ac03d..35228748f0662 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -235,7 +235,7 @@ impl<'a> base::Resolver for Resolver<'a> { if name == "derive" { let result = attrs[i].parse_list(&self.session.parse_sess, |parser| { - parser.parse_path_allowing_meta(PathStyle::Mod) + parser.parse_path(PathStyle::Mod) }); let mut traits = match result { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index b590a4a628608..bc457f49fcffd 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -474,10 +474,10 @@ pub enum NestedMetaItemKind { /// A spanned compile-time attribute item. /// -/// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]` +/// E.g. `#[test]`, `#[derive(..)]`, `#[rustfmt::skip]` or `#[feature = "foo"]` #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct MetaItem { - pub ident: Ident, + pub name: Path, pub node: MetaItemKind, pub span: Span, } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index f0557277267a5..7a0231dc3f447 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -137,7 +137,7 @@ impl NestedMetaItem { /// 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.ident.name)) + 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 @@ -154,7 +154,7 @@ impl NestedMetaItem { if meta_item_list.len() == 1 { let nested_item = &meta_item_list[0]; if nested_item.is_literal() { - Some((meta_item.ident.name, nested_item.literal().unwrap())) + Some((meta_item.name(), nested_item.literal().unwrap())) } else { None } @@ -204,6 +204,10 @@ impl NestedMetaItem { } } +fn name_from_path(path: &ast::Path) -> Name { + path.segments.iter().next().unwrap().identifier.name +} + impl Attribute { pub fn check_name(&self, name: &str) -> bool { let matches = self.path == name; @@ -215,7 +219,7 @@ impl Attribute { pub fn name(&self) -> Option { match self.path.segments.len() { - 1 => Some(self.path.segments[0].ident.name), + 1 => Some(self.path.segments[0].identifier.name), _ => None, } } @@ -250,6 +254,10 @@ impl Attribute { } impl MetaItem { + pub fn name(&self) -> Name { + name_from_path(&self.name) + } + pub fn value_str(&self) -> Option { match self.node { MetaItemKind::NameValue(ref v) => { @@ -279,7 +287,7 @@ impl MetaItem { pub fn span(&self) -> Span { self.span } pub fn check_name(&self, name: &str) -> bool { - self.ident.name == name + self.name() == name } pub fn is_value_str(&self) -> bool { @@ -296,10 +304,7 @@ impl Attribute { pub fn meta(&self) -> Option { let mut tokens = self.tokens.trees().peekable(); Some(MetaItem { - ident: match self.path.segments.len() { - 1 => self.path.segments[0].ident, - _ => return None, - }, + name: self.path.clone(), node: if let Some(node) = MetaItemKind::from_tokens(&mut tokens) { if tokens.peek().is_some() { return None; @@ -344,12 +349,8 @@ impl Attribute { } pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> { - if self.path.segments.len() > 1 { - sess.span_diagnostic.span_err(self.path.span, "expected ident, found path"); - } - Ok(MetaItem { - ident: self.path.segments.last().unwrap().ident, + name: self.path.clone(), node: self.parse(sess, |parser| parser.parse_meta_item_kind())?, span: self.span, }) @@ -397,8 +398,31 @@ pub fn mk_list_item(span: Span, ident: Ident, items: Vec) -> Met pub fn mk_word_item(ident: Ident) -> MetaItem { MetaItem { ident, span: ident.span, node: MetaItemKind::Word } } -pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem { - respan(ident.span, NestedMetaItemKind::MetaItem(mk_word_item(ident))) + +pub fn mk_word_item(name: Name) -> MetaItem { + mk_spanned_word_item(DUMMY_SP, name) +} + +macro_rules! mk_spanned_meta_item { + ($sp:ident, $name:ident, $node:expr) => { + MetaItem { + span: $sp, + name: ast::Path::from_ident($sp, ast::Ident::with_empty_ctxt($name)), + node: $node, + } + } +} + +pub fn mk_spanned_name_value_item(sp: Span, name: Name, value: ast::Lit) -> MetaItem { + mk_spanned_meta_item!(sp, name, MetaItemKind::NameValue(value)) +} + +pub fn mk_spanned_list_item(sp: Span, name: Name, items: Vec) -> MetaItem { + mk_spanned_meta_item!(sp, name, MetaItemKind::List(items)) +} + +pub fn mk_spanned_word_item(sp: Span, name: Name) -> MetaItem { + mk_spanned_meta_item!(sp, name, MetaItemKind::Word) } pub fn mk_attr_id() -> AttrId { @@ -422,7 +446,7 @@ pub fn mk_spanned_attr_inner(sp: Span, id: AttrId, item: MetaItem) -> Attribute Attribute { id, style: ast::AttrStyle::Inner, - path: ast::Path::from_ident(item.ident), + path: item.name, tokens: item.node.tokens(item.span), is_sugared_doc: false, span: sp, @@ -440,7 +464,7 @@ pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute Attribute { id, style: ast::AttrStyle::Outer, - path: ast::Path::from_ident(item.ident), + path: item.name, tokens: item.node.tokens(item.span), is_sugared_doc: false, span: sp, @@ -489,7 +513,7 @@ pub fn contains_feature_attr(attrs: &[Attribute], feature_name: &str) -> bool { item.check_name("feature") && item.meta_item_list().map(|list| { list.iter().any(|mi| { - mi.word().map(|w| w.ident.name == feature_name) + mi.word().map(|w| w.name() == feature_name) .unwrap_or(false) }) }).unwrap_or(false) @@ -562,7 +586,7 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat if let (Some(feats), Some(gated_cfg)) = (features, GatedCfg::gate(cfg)) { gated_cfg.check_and_emit(sess, feats); } - sess.config.contains(&(cfg.ident.name, cfg.value_str())) + sess.config.contains(&(cfg.name(), cfg.value_str())) }) } @@ -583,7 +607,7 @@ 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.ident.name.as_str() { + match &*cfg.name().as_str() { "any" => mis.iter().any(|mi| { eval_condition(mi.meta_item().unwrap(), sess, eval) }), @@ -676,7 +700,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, let meta = meta.as_ref().unwrap(); let get = |meta: &MetaItem, item: &mut Option| { if item.is_some() { - handle_errors(diagnostic, meta.span, AttrError::MultipleItem(meta.ident.name)); + handle_errors(diagnostic, meta.span, AttrError::MultipleItem(meta.name())); return false } if let Some(v) = meta.value_str() { @@ -695,14 +719,14 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, )+ for meta in metas { if let Some(mi) = meta.meta_item() { - match &*mi.ident.name.as_str() { + match &*mi.name().as_str() { $( stringify!($name) => if !get(mi, &mut $name) { continue 'outer }, )+ _ => { handle_errors(diagnostic, mi.span, - AttrError::UnknownMetaItem(mi.ident.name)); + AttrError::UnknownMetaItem(mi.name())); continue 'outer } } @@ -714,7 +738,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, } } - match &*meta.ident.name.as_str() { + match &*meta.name().as_str() { "rustc_deprecated" => { if rustc_depr.is_some() { span_err!(diagnostic, item_sp, E0540, @@ -769,13 +793,13 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, let mut issue = None; for meta in metas { if let Some(mi) = meta.meta_item() { - match &*mi.ident.name.as_str() { + 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 }, _ => { handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(mi.ident.name)); + AttrError::UnknownMetaItem(mi.name())); continue 'outer } } @@ -825,12 +849,12 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, let mut since = None; for meta in metas { if let NestedMetaItemKind::MetaItem(ref mi) = meta.node { - match &*mi.ident.name.as_str() { + match &*mi.name().as_str() { "feature" => if !get(mi, &mut feature) { continue 'outer }, "since" => if !get(mi, &mut since) { continue 'outer }, _ => { handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(mi.ident.name)); + AttrError::UnknownMetaItem(mi.name())); continue 'outer } } @@ -917,7 +941,7 @@ fn find_deprecation_generic<'a, I>(diagnostic: &Handler, depr = if let Some(metas) = attr.meta_item_list() { let get = |meta: &MetaItem, item: &mut Option| { if item.is_some() { - handle_errors(diagnostic, meta.span, AttrError::MultipleItem(meta.ident.name)); + handle_errors(diagnostic, meta.span, AttrError::MultipleItem(meta.name())); return false } if let Some(v) = meta.value_str() { @@ -933,12 +957,12 @@ fn find_deprecation_generic<'a, I>(diagnostic: &Handler, let mut note = None; for meta in metas { if let NestedMetaItemKind::MetaItem(ref mi) = meta.node { - match &*mi.ident.name.as_str() { + match &*mi.name().as_str() { "since" => if !get(mi, &mut since) { continue 'outer }, "note" => if !get(mi, &mut note) { continue 'outer }, _ => { handle_errors(diagnostic, meta.span, - AttrError::UnknownMetaItem(mi.ident.name)); + AttrError::UnknownMetaItem(mi.name())); continue 'outer } } @@ -990,7 +1014,7 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec let mut recognised = false; if let Some(mi) = item.word() { - let word = &*mi.ident.name.as_str(); + let word = &*mi.name().as_str(); let hint = match word { "C" => Some(ReprC), "packed" => Some(ReprPacked(1)), @@ -1127,18 +1151,52 @@ impl IntType { impl MetaItem { fn tokens(&self) -> TokenStream { - let ident = TokenTree::Token(self.span, Token::from_ast_ident(self.ident)); - TokenStream::concat(vec![ident.into(), self.node.tokens(self.span)]) + let mut idents = vec![]; + let mut last_pos = BytePos(0 as u32); + for (i, segment) in self.name.segments.iter().enumerate() { + let is_first = i == 0; + if !is_first { + let mod_sep_span = Span::new(last_pos, segment.span.lo(), segment.span.ctxt()); + idents.push(TokenTree::Token(mod_sep_span, Token::ModSep).into()); + } + idents.push(TokenTree::Token(segment.span, Token::Ident(segment.identifier)).into()); + last_pos = segment.span.hi(); + } + idents.push(self.node.tokens(self.span)); + TokenStream::concat(idents) } fn from_tokens(tokens: &mut iter::Peekable) -> Option where I: Iterator, { - let (span, ident) = match tokens.next() { - Some(TokenTree::Token(span, Token::Ident(ident, _))) => (span, ident), + let name = match tokens.next() { + Some(TokenTree::Token(span, Token::Ident(ident))) => { + if let Some(TokenTree::Token(_, Token::ModSep)) = tokens.peek() { + tokens.next(); + let mut segments = vec![]; + loop { + if let Some(TokenTree::Token(span, Token::Ident(ident))) = tokens.next() { + segments.push(ast::PathSegment::from_ident(ident, span)); + } else { + return None; + } + if let Some(TokenTree::Token(_, Token::ModSep)) = tokens.peek() { + tokens.next(); + } else { + break; + } + } + ast::Path { span, segments } + } else { + ast::Path::from_ident(span, ident) + } + } Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => match nt.0 { - token::Nonterminal::NtIdent(ident, _) => (ident.span, ident), + token::Nonterminal::NtIdent(ident) => { + ast::Path::from_ident(ident.span, ident.node) + } token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()), + token::Nonterminal::NtPath(ref path) => path.clone(), _ => return None, }, _ => return None, @@ -1147,10 +1205,11 @@ impl MetaItem { let node = MetaItemKind::from_tokens(tokens)?; let hi = match node { MetaItemKind::NameValue(ref lit) => lit.span.hi(), - MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(span.hi()), - _ => span.hi(), + MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(name.span.hi()), + _ => name.span.hi(), }; - Some(MetaItem { ident, node, span: span.with_hi(hi) }) + let span = name.span.with_hi(hi); + Some(MetaItem { name, node, span }) } } diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 6bf166dfe950a..afb233533bad6 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -26,8 +26,7 @@ pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec return true; } - match attr.parse_list(cx.parse_sess, - |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) { + match attr.parse_list(cx.parse_sess, |parser| parser.parse_path(PathStyle::Mod)) { Ok(ref traits) if traits.is_empty() => { cx.span_warn(attr.span, "empty trait list in `derive`"); false diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 2f3b35c33f3ec..1d16a7eb09145 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -810,7 +810,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { invoc.expansion_data.mark.set_expn_info(expn_info); let span = span.with_ctxt(self.cx.backtrace()); let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this - ident: keywords::Invalid.ident(), + name: Path::from_ident(DUMMY_SP, keywords::Invalid.ident()), span: DUMMY_SP, node: ast::MetaItemKind::Word, }; diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 90f08ab1468e2..0671f29648f91 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -149,7 +149,7 @@ impl<'a> Parser<'a> { }; Ok(if let Some(meta) = meta { self.bump(); - (ast::Path::from_ident(meta.ident), meta.node.tokens(meta.span)) + (meta.name, meta.node.tokens(meta.span)) } else { (self.parse_path(PathStyle::Mod)?, self.parse_tokens()) }) @@ -225,9 +225,10 @@ impl<'a> Parser<'a> { } let lo = self.span; - let ident = self.parse_ident()?; + let name = self.parse_path(PathStyle::Mod)?; let node = self.parse_meta_item_kind()?; - Ok(ast::MetaItem { ident, node: node, span: lo.to(self.prev_span) }) + let span = lo.to(self.prev_span); + Ok(ast::MetaItem { name, node, span }) } pub fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 88860df10e2c3..e8beb7e442c0b 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -714,6 +714,22 @@ pub trait PrintState<'a> { Ok(()) } + fn print_attribute_path(&mut self, path: &ast::Path) -> io::Result<()> { + for (i, segment) in path.segments.iter().enumerate() { + if i > 0 { + self.writer().word("::")? + } + if segment.identifier.name != keywords::CrateRoot.name() && + segment.identifier.name != keywords::DollarCrate.name() + { + self.writer().word(&segment.identifier.name.as_str())?; + } else if segment.identifier.name == keywords::DollarCrate.name() { + self.print_dollar_crate(segment.identifier.ctxt)?; + } + } + Ok(()) + } + fn print_attribute(&mut self, attr: &ast::Attribute) -> io::Result<()> { self.print_attribute_inline(attr, false) } @@ -735,17 +751,7 @@ pub trait PrintState<'a> { if let Some(mi) = attr.meta() { self.print_meta_item(&mi)? } else { - for (i, segment) in attr.path.segments.iter().enumerate() { - if i > 0 { - self.writer().word("::")? - } - if segment.ident.name != keywords::CrateRoot.name() && - segment.ident.name != keywords::DollarCrate.name() { - self.writer().word(&segment.ident.name.as_str())?; - } else if segment.ident.name == keywords::DollarCrate.name() { - self.print_dollar_crate(segment.ident.span.ctxt())?; - } - } + self.print_attribute_path(&attr.path)?; self.writer().space()?; self.print_tts(attr.tokens.clone())?; } @@ -767,16 +773,14 @@ pub trait PrintState<'a> { fn print_meta_item(&mut self, item: &ast::MetaItem) -> io::Result<()> { self.ibox(INDENT_UNIT)?; match item.node { - ast::MetaItemKind::Word => { - self.writer().word(&item.ident.name.as_str())?; - } + ast::MetaItemKind::Word => self.print_attribute_path(&item.name)?, ast::MetaItemKind::NameValue(ref value) => { - self.word_space(&item.ident.name.as_str())?; + self.print_attribute_path(&item.name)?; self.word_space("=")?; self.print_literal(value)?; } ast::MetaItemKind::List(ref items) => { - self.writer().word(&item.ident.name.as_str())?; + self.print_attribute_path(&item.name)?; self.popen()?; self.commasep(Consistent, &items[..],