From 28ed8b159237a2704f2308a404b3bd81b676ce17 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 15 Aug 2016 21:28:17 +0300 Subject: [PATCH 01/18] Fix #[derive] for empty tuple structs/variants --- src/libsyntax/ext/build.rs | 2 +- src/libsyntax_ext/deriving/decodable.rs | 6 ++--- src/libsyntax_ext/deriving/default.rs | 4 ++-- src/libsyntax_ext/deriving/generic/mod.rs | 6 ++--- .../empty-struct-braces-derive.rs | 24 ++++++++++++++++++- 5 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 5d6429f7bdfff..7600bff96952d 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -844,7 +844,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn pat_enum(&self, span: Span, path: ast::Path, subpats: Vec>) -> P { let pat = if subpats.is_empty() { - PatKind::Path(None, path) + PatKind::Struct(path, Vec::new(), false) } else { PatKind::TupleStruct(path, subpats, None) }; diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs index 9a332227053c7..f395f7bd0c4c4 100644 --- a/src/libsyntax_ext/deriving/decodable.rs +++ b/src/libsyntax_ext/deriving/decodable.rs @@ -110,7 +110,7 @@ fn decodable_substructure(cx: &mut ExtCtxt, return match *substr.fields { StaticStruct(_, ref summary) => { let nfields = match *summary { - Unnamed(ref fields) => fields.len(), + Unnamed(ref fields, _) => fields.len(), Named(ref fields) => fields.len(), }; let read_struct_field = cx.ident_of("read_struct_field"); @@ -193,9 +193,9 @@ fn decode_static_fields(cx: &mut ExtCtxt, where F: FnMut(&mut ExtCtxt, Span, InternedString, usize) -> P { match *fields { - Unnamed(ref fields) => { + Unnamed(ref fields, is_tuple) => { let path_expr = cx.expr_path(outer_pat_path); - if fields.is_empty() { + if !is_tuple { path_expr } else { let fields = fields.iter() diff --git a/src/libsyntax_ext/deriving/default.rs b/src/libsyntax_ext/deriving/default.rs index 9df3db938b1f9..449c1ff066b3b 100644 --- a/src/libsyntax_ext/deriving/default.rs +++ b/src/libsyntax_ext/deriving/default.rs @@ -57,8 +57,8 @@ fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructur return match *substr.fields { StaticStruct(_, ref summary) => { match *summary { - Unnamed(ref fields) => { - if fields.is_empty() { + Unnamed(ref fields, is_tuple) => { + if !is_tuple { cx.expr_ident(trait_span, substr.type_ident) } else { let exprs = fields.iter().map(|sp| default_call(*sp)).collect(); diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index cd49e7ec9d2c6..22e98fb213f95 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -294,8 +294,8 @@ pub struct FieldInfo<'a> { /// Fields for a static method pub enum StaticFields { - /// Tuple structs/enum variants like this. - Unnamed(Vec), + /// Tuple and unit structs/enum variants like this. + Unnamed(Vec, bool /*is tuple*/), /// Normal structs/struct variants. Named(Vec<(Ident, Span)>), } @@ -1470,7 +1470,7 @@ impl<'a> TraitDef<'a> { (_, false) => Named(named_idents), // empty structs _ if struct_def.is_struct() => Named(named_idents), - _ => Unnamed(just_spans), + _ => Unnamed(just_spans, struct_def.is_tuple()), } } diff --git a/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs b/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs index 8d19209208dc4..66ffff94333e9 100644 --- a/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs +++ b/src/test/run-pass-fulldeps/empty-struct-braces-derive.rs @@ -8,8 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// `#[derive(Trait)]` works for empty structs/variants with braces +// `#[derive(Trait)]` works for empty structs/variants with braces or parens. +#![feature(relaxed_adts)] #![feature(rustc_private)] extern crate serialize as rustc_serialize; @@ -18,11 +19,16 @@ extern crate serialize as rustc_serialize; Default, Debug, RustcEncodable, RustcDecodable)] struct S {} +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, + Default, Debug, RustcEncodable, RustcDecodable)] +struct Z(); + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] enum E { V {}, U, + W(), } fn main() { @@ -34,6 +40,14 @@ fn main() { assert!(!(s < s1)); assert_eq!(format!("{:?}", s), "S"); + let z = Z(); + let z1 = z; + let z2 = z.clone(); + assert_eq!(z, z1); + assert_eq!(z, z2); + assert!(!(z < z1)); + assert_eq!(format!("{:?}", z), "Z"); + let e = E::V {}; let e1 = e; let e2 = e.clone(); @@ -41,4 +55,12 @@ fn main() { assert_eq!(e, e2); assert!(!(e < e1)); assert_eq!(format!("{:?}", e), "V"); + + let e = E::W(); + let e1 = e; + let e2 = e.clone(); + assert_eq!(e, e1); + assert_eq!(e, e2); + assert!(!(e < e1)); + assert_eq!(format!("{:?}", e), "W"); } From f6e06a8a365b118937079e3f9c4dfa8f221e7db5 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 15 Aug 2016 21:28:17 +0300 Subject: [PATCH 02/18] Split `AstBuilder::pat_enum` into `pat_tuple_struct` and `pat_path` --- src/libsyntax/ext/build.rs | 40 ++++++++-------- src/libsyntax_ext/deriving/cmp/ord.rs | 2 +- src/libsyntax_ext/deriving/cmp/partial_ord.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 46 +++++++++++-------- 4 files changed, 48 insertions(+), 42 deletions(-) diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 7600bff96952d..507e46ea59e9e 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -171,9 +171,11 @@ pub trait AstBuilder { span: Span, ident: ast::Ident, bm: ast::BindingMode) -> P; - fn pat_enum(&self, span: Span, path: ast::Path, subpats: Vec> ) -> P; - fn pat_struct(&self, span: Span, - path: ast::Path, field_pats: Vec> ) -> P; + fn pat_path(&self, span: Span, path: ast::Path) -> P; + fn pat_tuple_struct(&self, span: Span, path: ast::Path, + subpats: Vec>) -> P; + fn pat_struct(&self, span: Span, path: ast::Path, + field_pats: Vec>) -> P; fn pat_tuple(&self, span: Span, pats: Vec>) -> P; fn pat_some(&self, span: Span, pat: P) -> P; @@ -802,10 +804,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 +844,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 { - let pat = if subpats.is_empty() { - PatKind::Struct(path, Vec::new(), false) - } else { - PatKind::TupleStruct(path, subpats, None) - }; - self.pat(span, pat) + fn pat_path(&self, span: Span, path: ast::Path) -> P { + self.pat(span, PatKind::Path(None, path)) } - fn pat_struct(&self, span: Span, - path: ast::Path, field_pats: Vec>) -> P { - 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 { + self.pat(span, PatKind::TupleStruct(path, subpats, None)) + } + fn pat_struct(&self, span: Span, path: ast::Path, + field_pats: Vec>) -> P { + self.pat(span, PatKind::Struct(path, field_pats, false)) } fn pat_tuple(&self, span: Span, pats: Vec>) -> P { self.pat(span, PatKind::Tuple(pats, None)) @@ -862,25 +862,25 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn pat_some(&self, span: Span, pat: P) -> P { 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 { 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) -> P { 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) -> P { 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>, expr: P) -> ast::Arm { diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs index 8ae77e79310b2..31194b04fa6e4 100644 --- a/src/libsyntax_ext/deriving/cmp/ord.rs +++ b/src/libsyntax_ext/deriving/cmp/ord.rs @@ -104,7 +104,7 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { }; let eq_arm = cx.arm(span, - vec![cx.pat_enum(span, equals_path.clone(), vec![])], + vec![cx.pat_path(span, equals_path.clone())], old); let neq_arm = cx.arm(span, vec![cx.pat_ident(span, test_id)], diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index 10a9738742e44..9e9b2f020622f 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -165,7 +165,7 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P< }; let eq_arm = cx.arm(span, - vec![cx.pat_some(span, cx.pat_enum(span, ordering.clone(), vec![]))], + vec![cx.pat_some(span, cx.pat_path(span, ordering.clone()))], old); let neq_arm = cx.arm(span, vec![cx.pat_ident(span, test_id)], diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 22e98fb213f95..b2b887c7ef2d4 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -1510,26 +1510,32 @@ impl<'a> TraitDef<'a> { } let subpats = self.create_subpatterns(cx, paths, mutbl); - let pattern = if struct_def.is_struct() { - let field_pats = subpats.into_iter() - .zip(&ident_exprs) - .map(|(pat, &(sp, ident, _, _))| { - if ident.is_none() { - cx.span_bug(sp, "a braced struct with unnamed fields in `derive`"); - } - codemap::Spanned { - span: pat.span, - node: ast::FieldPat { - ident: ident.unwrap(), - pat: pat, - is_shorthand: false, - }, - } - }) - .collect(); - cx.pat_struct(self.span, struct_path, field_pats) - } else { - cx.pat_enum(self.span, struct_path, subpats) + let pattern = match *struct_def { + VariantData::Struct(..) => { + let field_pats = subpats.into_iter() + .zip(&ident_exprs) + .map(|(pat, &(sp, ident, _, _))| { + if ident.is_none() { + cx.span_bug(sp, "a braced struct with unnamed fields in `derive`"); + } + codemap::Spanned { + span: pat.span, + node: ast::FieldPat { + ident: ident.unwrap(), + pat: pat, + is_shorthand: false, + }, + } + }) + .collect(); + cx.pat_struct(self.span, struct_path, field_pats) + } + VariantData::Tuple(..) => { + cx.pat_tuple_struct(self.span, struct_path, subpats) + } + VariantData::Unit(..) => { + cx.pat_path(self.span, struct_path) + } }; (pattern, ident_exprs) From 59481823675a7392e8160b659b0f7fa119df60fd Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 10 Aug 2016 19:39:12 +0200 Subject: [PATCH 03/18] Add Span field for Generics structs --- src/librustc/hir/fold.rs | 3 +- src/librustc/hir/lowering.rs | 1 + src/librustc/hir/mod.rs | 36 ++--------------------- src/librustc/hir/print.rs | 2 ++ src/librustc/infer/error_reporting.rs | 1 + src/librustc_typeck/lib.rs | 11 ++++--- src/libsyntax/ast.rs | 6 ++-- src/libsyntax/fold.rs | 3 +- src/libsyntax/parse/mod.rs | 5 ++-- src/libsyntax/parse/parser.rs | 8 +++-- src/libsyntax/print/pprust.rs | 2 ++ src/libsyntax_ext/deriving/generic/mod.rs | 3 +- src/libsyntax_ext/deriving/generic/ty.rs | 6 ++-- src/test/compile-fail/E0132.rs | 2 +- 14 files changed, 37 insertions(+), 52 deletions(-) diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs index 0edfd16bdfd1b..0b362bac8882b 100644 --- a/src/librustc/hir/fold.rs +++ b/src/librustc/hir/fold.rs @@ -577,13 +577,14 @@ pub fn noop_fold_opt_lifetime(o_lt: Option, fld: &mut T) -> o_lt.map(|lt| fld.fold_lifetime(lt)) } -pub fn noop_fold_generics(Generics { ty_params, lifetimes, where_clause }: Generics, +pub fn noop_fold_generics(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), } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index c2b211238b2f1..cb219bbe18ae8 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -466,6 +466,7 @@ impl<'a> LoweringContext<'a> { ty_params: self.lower_ty_params(&g.ty_params), lifetimes: self.lower_lifetime_defs(&g.lifetimes), where_clause: self.lower_where_clause(&g.where_clause), + span: g.span, } } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index d41cdfabdf4c0..f351384c2b89e 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -36,7 +36,7 @@ use hir::def::Def; use hir::def_id::DefId; use util::nodemap::{NodeMap, FnvHashSet}; -use syntax_pos::{BytePos, mk_sp, Span, ExpnId}; +use syntax_pos::{mk_sp, Span, ExpnId, DUMMY_SP}; use syntax::codemap::{self, respan, Spanned}; use syntax::abi::Abi; use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect}; @@ -301,6 +301,7 @@ pub struct Generics { pub lifetimes: HirVec, pub ty_params: HirVec, pub where_clause: WhereClause, + pub span: Span, } impl Generics { @@ -312,6 +313,7 @@ impl Generics { id: DUMMY_NODE_ID, predicates: HirVec::new(), }, + span: DUMMY_SP, } } @@ -326,38 +328,6 @@ impl Generics { pub fn is_parameterized(&self) -> bool { self.is_lt_parameterized() || self.is_type_parameterized() } - - // Does return a span which includes lifetimes and type parameters, - // not where clause. - pub fn span(&self) -> Option { - if !self.is_parameterized() { - None - } else { - let mut span: Option = None; - for lifetime in self.lifetimes.iter() { - if let Some(ref mut span) = span { - let life_span = lifetime.lifetime.span; - span.hi = if span.hi > life_span.hi { span.hi } else { life_span.hi }; - span.lo = if span.lo < life_span.lo { span.lo } else { life_span.lo }; - } else { - span = Some(lifetime.lifetime.span.clone()); - } - } - for ty_param in self.ty_params.iter() { - if let Some(ref mut span) = span { - span.lo = if span.lo < ty_param.span.lo { span.lo } else { ty_param.span.lo }; - span.hi = if span.hi > ty_param.span.hi { span.hi } else { ty_param.span.hi }; - } else { - span = Some(ty_param.span.clone()); - } - } - if let Some(ref mut span) = span { - span.lo = span.lo - BytePos(1); - span.hi = span.hi + BytePos(1); - } - span - } - } } /// A `where` clause in a definition diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 66c1bc7642c56..1cbead123d871 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -523,6 +523,7 @@ impl<'a> State<'a> { id: ast::DUMMY_NODE_ID, predicates: hir::HirVec::new(), }, + span: syntax_pos::DUMMY_SP, }; self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &generics)?; } @@ -2224,6 +2225,7 @@ impl<'a> State<'a> { id: ast::DUMMY_NODE_ID, predicates: hir::HirVec::new(), }, + span: syntax_pos::DUMMY_SP, }; self.print_fn(decl, unsafety, diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 9a6375719c1bc..03ad12d2d99f8 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -1293,6 +1293,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { lifetimes: lifetimes.into(), ty_params: ty_params, where_clause: where_clause, + span: generics.span, } } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 8a8232535c775..b24eb8cba1cf3 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -216,10 +216,10 @@ fn check_main_fn_ty(ccx: &CrateCtxt, Some(hir_map::NodeItem(it)) => { match it.node { hir::ItemFn(_, _, _, _, ref generics, _) => { - if let Some(gen_span) = generics.span() { - struct_span_err!(ccx.tcx.sess, gen_span, E0131, + if generics.is_parameterized() { + struct_span_err!(ccx.tcx.sess, generics.span, E0131, "main function is not allowed to have type parameters") - .span_label(gen_span, + .span_label(generics.span, &format!("main cannot have type parameters")) .emit(); return; @@ -269,10 +269,9 @@ fn check_start_fn_ty(ccx: &CrateCtxt, match it.node { hir::ItemFn(_,_,_,_,ref ps,_) if ps.is_parameterized() => { - let sp = if let Some(sp) = ps.span() { sp } else { start_span }; - struct_span_err!(tcx.sess, sp, E0132, + struct_span_err!(tcx.sess, ps.span, E0132, "start function is not allowed to have type parameters") - .span_label(sp, + .span_label(ps.span, &format!("start function cannot have type parameters")) .emit(); return; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f8a5cb0b04a8e..968956d3391a0 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>, - 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, 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, } } } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index b257ab98987dc..c566aa5661be0 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -698,12 +698,13 @@ pub fn noop_fold_opt_lifetime(o_lt: Option, fld: &mut T) o_lt.map(|lt| fld.fold_lifetime(lt)) } -pub fn noop_fold_generics(Generics {ty_params, lifetimes, where_clause}: Generics, +pub fn noop_fold_generics(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), } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index cd1fdcfe9d130..eb59a8e24d3fd 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -674,7 +674,7 @@ 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; @@ -945,7 +945,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 126e8816d0559..19f44924067db 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -716,8 +716,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))) } } } @@ -4251,6 +4251,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()?; @@ -4273,7 +4274,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()) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index a77c678248b56..22b0bb2c07ad0 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1001,6 +1001,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, @@ -2982,6 +2983,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_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index cd49e7ec9d2c6..6773088670f58 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -488,7 +488,7 @@ impl<'a> TraitDef<'a> { } }); - let Generics { mut lifetimes, ty_params, mut where_clause } = self.generics + let Generics { mut lifetimes, ty_params, mut where_clause, span } = self.generics .to_generics(cx, self.span, type_ident, generics); let mut ty_params = ty_params.into_vec(); @@ -590,6 +590,7 @@ impl<'a> TraitDef<'a> { lifetimes: lifetimes, ty_params: P::from_vec(ty_params), where_clause: where_clause, + span: span, }; // Create the reference to the trait. diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs index 356c54fcf3120..210878b7c9f0e 100644 --- a/src/libsyntax_ext/deriving/generic/ty.rs +++ b/src/libsyntax_ext/deriving/generic/ty.rs @@ -207,7 +207,8 @@ fn mk_ty_param(cx: &ExtCtxt, cx.typaram(span, cx.ident_of(name), bounds, None) } -fn mk_generics(lifetimes: Vec, ty_params: Vec) -> Generics { +fn mk_generics(lifetimes: Vec, ty_params: Vec, span: Span) + -> Generics { Generics { lifetimes: lifetimes, ty_params: P::from_vec(ty_params), @@ -215,6 +216,7 @@ fn mk_generics(lifetimes: Vec, ty_params: Vec) - id: ast::DUMMY_NODE_ID, predicates: Vec::new(), }, + span: span, } } @@ -257,7 +259,7 @@ impl<'a> LifetimeBounds<'a> { } }) .collect(); - mk_generics(lifetimes, ty_params) + mk_generics(lifetimes, ty_params, span) } } diff --git a/src/test/compile-fail/E0132.rs b/src/test/compile-fail/E0132.rs index 1a33fb24ca1a1..91ff6b85a42ce 100644 --- a/src/test/compile-fail/E0132.rs +++ b/src/test/compile-fail/E0132.rs @@ -11,7 +11,7 @@ #![feature(start)] #[start] -fn f() {} //~ ERROR E0132 +fn f< T >() {} //~ ERROR E0132 //~| NOTE start function cannot have type parameters fn main() { From 98ce875b58a87164b763e83be82b5ed32f4398a9 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 12 Aug 2016 09:01:22 +0000 Subject: [PATCH 04/18] Refactor away variant `ast::PathListItemKind::Mod` and refactor `ast::PathListItemKind::Ident` -> `ast::PathListItem_`. --- src/librustc/hir/lowering.rs | 14 +++----- src/librustc_resolve/build_reduced_graph.rs | 25 +++++++------ src/librustc_resolve/check_unused.rs | 2 +- src/librustc_save_analysis/dump_visitor.rs | 17 +++------ src/libsyntax/ast.rs | 40 ++++----------------- src/libsyntax/ext/build.rs | 2 +- src/libsyntax/fold.rs | 16 +++------ src/libsyntax/parse/parser.rs | 15 ++++---- src/libsyntax/print/pprust.rs | 25 ++++--------- src/libsyntax/visit.rs | 4 +-- 10 files changed, 52 insertions(+), 108 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index c2b211238b2f1..afb8f5de8eadd 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -218,16 +218,10 @@ impl<'a> LoweringContext<'a> { fn lower_path_list_item(&mut self, path_list_ident: &PathListItem) -> hir::PathListItem { Spanned { - node: match path_list_ident.node { - PathListItemKind::Ident { id, name, rename } => hir::PathListIdent { - id: id, - name: name.name, - rename: rename.map(|x| x.name), - }, - PathListItemKind::Mod { id, rename } => hir::PathListMod { - id: id, - rename: rename.map(|x| x.name), - }, + node: hir::PathListIdent { + id: path_list_ident.node.id, + name: path_list_ident.node.name.name, + rename: path_list_ident.node.rename.map(|rename| rename.name), }, span: path_list_ident.span, } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 579853446525e..12c55b3ac172c 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -32,9 +32,9 @@ use syntax::parse::token; use syntax::ast::{Block, Crate}; use syntax::ast::{ForeignItem, ForeignItemKind, Item, ItemKind}; -use syntax::ast::{Mutability, PathListItemKind}; -use syntax::ast::{StmtKind, TraitItemKind}; +use syntax::ast::{Mutability, StmtKind, TraitItemKind}; use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}; +use syntax::parse::token::keywords; use syntax::visit::{self, Visitor}; use syntax_pos::{Span, DUMMY_SP}; @@ -130,9 +130,10 @@ impl<'b> Resolver<'b> { ViewPathList(_, ref source_items) => { // Make sure there's at most one `mod` import in the list. let mod_spans = source_items.iter().filter_map(|item| { - match item.node { - PathListItemKind::Mod { .. } => Some(item.span), - _ => None, + if item.node.name.name == keywords::SelfValue.name() { + Some(item.span) + } else { + None } }).collect::>(); @@ -147,10 +148,12 @@ impl<'b> Resolver<'b> { } for source_item in source_items { - let (module_path, name, rename) = match source_item.node { - PathListItemKind::Ident { name, rename, .. } => - (module_path.clone(), name.name, rename.unwrap_or(name).name), - PathListItemKind::Mod { rename, .. } => { + let node = source_item.node; + let (module_path, name, rename) = { + if node.name.name != keywords::SelfValue.name() { + let rename = node.rename.unwrap_or(node.name).name; + (module_path.clone(), node.name.name, rename) + } else { let name = match module_path.last() { Some(name) => *name, None => { @@ -164,12 +167,12 @@ impl<'b> Resolver<'b> { } }; let module_path = module_path.split_last().unwrap().1; - let rename = rename.map(|i| i.name).unwrap_or(name); + let rename = node.rename.map(|i| i.name).unwrap_or(name); (module_path.to_vec(), name, rename) } }; let subclass = ImportDirectiveSubclass::single(rename, name); - let (span, id) = (source_item.span, source_item.node.id()); + let (span, id) = (source_item.span, source_item.node.id); self.add_import_directive(module_path, subclass, span, id, vis); } } diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 3084d9abbe1e4..bc923ba29ca47 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -101,7 +101,7 @@ impl<'a, 'b> Visitor for UnusedImportCheckVisitor<'a, 'b> { ViewPathList(_, ref list) => { for i in list { - self.check_import(i.node.id(), i.span); + self.check_import(i.node.id, i.span); } } ViewPathGlob(_) => { diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 5e967f3250f71..dbe956f021e4c 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1102,18 +1102,11 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> } ast::ViewPathList(ref path, ref list) => { for plid in list { - match plid.node { - ast::PathListItemKind::Ident { id, .. } => { - let scope = self.cur_scope; - if let Some(def_id) = self.lookup_type_ref(id) { - self.process_def_kind(id, - plid.span, - Some(plid.span), - def_id, - scope); - } - } - ast::PathListItemKind::Mod { .. } => (), + let scope = self.cur_scope; + let id = plid.node.id; + if let Some(def_id) = self.lookup_type_ref(id) { + let span = plid.span; + self.process_def_kind(id, span, Some(span), def_id, scope); } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f8a5cb0b04a8e..8265798e796f3 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1624,42 +1624,14 @@ pub struct Variant_ { pub type Variant = Spanned; #[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, - id: NodeId - }, - Mod { - /// renamed in list, e.g. `use foo::{self as baz};` - rename: Option, - id: NodeId - } -} - -impl PathListItemKind { - pub fn id(&self) -> NodeId { - match *self { - PathListItemKind::Ident { id, .. } | PathListItemKind::Mod { id, .. } => id - } - } - - pub fn name(&self) -> Option { - match *self { - PathListItemKind::Ident { name, .. } => Some(name), - PathListItemKind::Mod { .. } => None, - } - } - - pub fn rename(&self) -> Option { - 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, + pub id: NodeId, } -pub type PathListItem = Spanned; +pub type PathListItem = Spanned; pub type ViewPath = Spanned; diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 5d6429f7bdfff..5d22930c4d59c 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -1178,7 +1178,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn item_use_list(&self, sp: Span, vis: ast::Visibility, path: Vec, imports: &[ast::Ident]) -> P { 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/fold.rs b/src/libsyntax/fold.rs index b257ab98987dc..9eb6217e50995 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -307,18 +307,10 @@ pub fn noop_fold_view_path(view_path: P, 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) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9443df6321bd0..63dbd325075c1 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -6017,13 +6017,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 a77c678248b56..65a5e06028fea 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2878,26 +2878,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, "}") } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 582412119caa8..1124a5414b86d 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -367,8 +367,8 @@ pub fn walk_path(visitor: &mut V, path: &Path) { } pub fn walk_path_list_item(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(visitor: &mut V, path_span: Span, segment: &PathSegment) { From c4d577be1acf333ff9c51c85fd1dd19adc46cb59 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 12 Aug 2016 09:15:02 +0000 Subject: [PATCH 05/18] Refactor away variant `hir::PathListItem_::Mod` and refacotor `hir::PathListItem_::Ident` -> `hir::PathListItem_`. --- src/librustc/hir/fold.rs | 14 +++-------- src/librustc/hir/intravisit.rs | 12 ++++----- src/librustc/hir/lowering.rs | 2 +- src/librustc/hir/map/collector.rs | 2 +- src/librustc/hir/mod.rs | 39 ++++------------------------- src/librustc/hir/print.rs | 11 +------- src/librustc/middle/dead.rs | 2 +- src/librustc/middle/stability.rs | 2 +- src/librustc_lint/unused.rs | 11 +++----- src/librustc_typeck/check_unused.rs | 2 +- 10 files changed, 25 insertions(+), 72 deletions(-) diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs index 0edfd16bdfd1b..5e4ca82dd0090 100644 --- a/src/librustc/hir/fold.rs +++ b/src/librustc/hir/fold.rs @@ -271,16 +271,10 @@ pub fn noop_fold_view_path(view_path: P, fld: &mut T) -> P< ViewPathList(fld.fold_path(path), path_list_idents.move_map(|path_list_ident| { Spanned { - node: match path_list_ident.node { - PathListIdent { id, name, rename } => PathListIdent { - id: fld.new_id(id), - name: name, - rename: rename, - }, - PathListMod { id, rename } => PathListMod { - id: fld.new_id(id), - rename: rename, - }, + node: PathListItem_ { + id: fld.new_id(path_list_ident.node.id), + name: path_list_ident.node.name, + rename: path_list_ident.node.rename, }, span: fld.new_span(path_list_ident.span), } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 92b956788860e..bc1dff7c6fc31 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -444,12 +444,12 @@ pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) { } } -pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V, - _prefix: &'v Path, - item: &'v PathListItem) { - visitor.visit_id(item.node.id()); - walk_opt_name(visitor, item.span, item.node.name()); - walk_opt_name(visitor, item.span, item.node.rename()); +pub fn walk_path_list_item<'v, V>(visitor: &mut V, _prefix: &'v Path, item: &'v PathListItem) + where V: Visitor<'v>, +{ + visitor.visit_id(item.node.id); + visitor.visit_name(item.span, item.node.name); + walk_opt_name(visitor, item.span, item.node.rename); } pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index afb8f5de8eadd..691396b9b7751 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -218,7 +218,7 @@ impl<'a> LoweringContext<'a> { fn lower_path_list_item(&mut self, path_list_ident: &PathListItem) -> hir::PathListItem { Spanned { - node: hir::PathListIdent { + node: hir::PathListItem_ { id: path_list_ident.node.id, name: path_list_ident.node.name.name, rename: path_list_ident.node.rename.map(|rename| rename.name), diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index b70190181af8f..280c0f3048569 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -120,7 +120,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { match view_path.node { ViewPathList(_, ref paths) => { for path in paths { - this.insert(path.node.id(), NodeItem(i)); + this.insert(path.node.id, NodeItem(i)); } } _ => () diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index d41cdfabdf4c0..d6b8a84698a87 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -20,7 +20,6 @@ pub use self::FunctionRetTy::*; pub use self::ForeignItem_::*; pub use self::Item_::*; pub use self::Mutability::*; -pub use self::PathListItem_::*; pub use self::PrimTy::*; pub use self::Stmt_::*; pub use self::TraitItem_::*; @@ -1337,39 +1336,11 @@ pub struct Variant_ { pub type Variant = Spanned; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub enum PathListItem_ { - PathListIdent { - name: Name, - /// renamed in list, eg `use foo::{bar as baz};` - rename: Option, - id: NodeId, - }, - PathListMod { - /// renamed in list, eg `use foo::{self as baz};` - rename: Option, - id: NodeId, - }, -} - -impl PathListItem_ { - pub fn id(&self) -> NodeId { - match *self { - PathListIdent { id, .. } | PathListMod { id, .. } => id, - } - } - - pub fn name(&self) -> Option { - match *self { - PathListIdent { name, .. } => Some(name), - PathListMod { .. } => None, - } - } - - pub fn rename(&self) -> Option { - match *self { - PathListIdent { rename, .. } | PathListMod { rename, .. } => rename, - } - } +pub struct PathListItem_ { + pub name: Name, + /// renamed in list, eg `use foo::{bar as baz};` + pub rename: Option, + pub id: NodeId, } pub type PathListItem = Spanned; diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 66c1bc7642c56..cdd8a36fbad6c 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -2133,16 +2133,7 @@ impl<'a> State<'a> { self.print_path(path, false, 0)?; word(&mut self.s, "::{")?; } - self.commasep(Inconsistent, &segments[..], |s, w| { - match w.node { - hir::PathListIdent { name, .. } => { - s.print_name(name) - } - hir::PathListMod { .. } => { - word(&mut s.s, "self") - } - } - })?; + self.commasep(Inconsistent, &segments[..], |s, w| s.print_name(w.node.name))?; word(&mut self.s, "}") } } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 2a8594c59a837..cdd774e11d328 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -294,7 +294,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> { } fn visit_path_list_item(&mut self, path: &hir::Path, item: &hir::PathListItem) { - self.lookup_and_handle_definition(item.node.id()); + self.lookup_and_handle_definition(item.node.id); intravisit::walk_path_list_item(self, path, item); } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index cbbc2c4f98f5e..6a57f510cdd9a 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -631,7 +631,7 @@ pub fn check_path_list_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cb: &mut FnMut(DefId, Span, &Option<&Stability>, &Option)) { - match tcx.expect_def(item.node.id()) { + match tcx.expect_def(item.node.id) { Def::PrimTy(..) => {} def => { maybe_do_stability_check(tcx, def.def_id(), item.span, cb); diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 57705301aab4e..1ec0bba5f5bcd 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -20,6 +20,7 @@ use std::collections::hash_map::Entry::{Occupied, Vacant}; use syntax::ast; use syntax::attr::{self, AttrMetaMethods}; use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType}; +use syntax::parse::token::keywords; use syntax::ptr::P; use syntax_pos::Span; @@ -392,13 +393,9 @@ impl LateLintPass for UnusedImportBraces { fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { if let hir::ItemUse(ref view_path) = item.node { if let hir::ViewPathList(_, ref items) = view_path.node { - if items.len() == 1 { - if let hir::PathListIdent {ref name, ..} = items[0].node { - let m = format!("braces around {} is unnecessary", - name); - cx.span_lint(UNUSED_IMPORT_BRACES, item.span, - &m[..]); - } + if items.len() == 1 && items[0].node.name != keywords::SelfValue.name() { + let msg = format!("braces around {} is unnecessary", items[0].node.name); + cx.span_lint(UNUSED_IMPORT_BRACES, item.span, &msg); } } } diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index 2ee0927f3c8ea..f66f15b238e73 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -49,7 +49,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for UnusedTraitImportVisitor<'a, 'tcx> { } hir::ViewPathList(_, ref path_list) => { for path_item in path_list { - self.check_import(path_item.node.id(), path_item.span); + self.check_import(path_item.node.id, path_item.span); } } } From 9d99fe98ad1980b8bc00678f27b2e324e584bea9 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 12 Aug 2016 23:09:41 +0000 Subject: [PATCH 06/18] Fix fallout in `rustdoc`. --- src/librustdoc/clean/mod.rs | 17 +++++------------ src/librustdoc/visit_ast.rs | 2 +- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 39b1a04e98e69..ad2452de33cfe 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2513,7 +2513,7 @@ impl Clean> for doctree::Import { let remaining = if !denied { let mut remaining = vec![]; for path in list { - match inline::try_inline(cx, path.node.id(), path.node.rename()) { + match inline::try_inline(cx, path.node.id, path.node.rename) { Some(items) => { ret.extend(items); } @@ -2581,17 +2581,10 @@ pub struct ViewListIdent { impl Clean for hir::PathListItem { fn clean(&self, cx: &DocContext) -> ViewListIdent { - match self.node { - hir::PathListIdent { id, name, rename } => ViewListIdent { - name: name.clean(cx), - rename: rename.map(|r| r.clean(cx)), - source: resolve_def(cx, id) - }, - hir::PathListMod { id, rename } => ViewListIdent { - name: "self".to_string(), - rename: rename.map(|r| r.clean(cx)), - source: resolve_def(cx, id) - } + ViewListIdent { + name: self.node.name.clean(cx), + rename: self.node.rename.map(|r| r.clean(cx)), + source: resolve_def(cx, self.node.id) } } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 0334c5ef5c4f4..d2da97666af07 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -189,7 +189,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } hir::ViewPathList(p, paths) => { let mine = paths.into_iter().filter(|path| { - !self.maybe_inline_local(path.node.id(), path.node.rename(), + !self.maybe_inline_local(path.node.id, path.node.rename, false, om, please_inline) }).collect::>(); From 8250a26b5bcea9190ac63e756c35d8a54bf9da0c Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Fri, 19 Aug 2016 18:58:14 -0700 Subject: [PATCH 07/18] Implement RFC#1559: allow all literals in attributes. --- src/librustc/hir/check_attr.rs | 19 +- src/librustc/hir/fold.rs | 23 +- src/librustc/lint/context.rs | 12 +- src/librustc_borrowck/borrowck/mir/mod.rs | 7 +- src/librustc_driver/lib.rs | 12 +- src/librustc_incremental/assert_dep_graph.rs | 39 ++- .../persist/dirty_clean.rs | 16 +- src/librustc_lint/builtin.rs | 6 +- src/librustc_lint/unused.rs | 7 + src/librustc_metadata/common.rs | 15 +- src/librustc_metadata/creader.rs | 3 +- src/librustc_metadata/decoder.rs | 51 +-- src/librustc_metadata/encoder.rs | 37 +- src/librustc_metadata/macro_import.rs | 11 +- src/librustc_plugin/load.rs | 20 +- src/librustc_plugin/registry.rs | 5 +- src/librustc_trans/assert_module_sources.rs | 2 +- src/librustdoc/clean/mod.rs | 56 ++- src/librustdoc/test.rs | 3 +- src/librustdoc/visit_ast.rs | 6 +- src/libsyntax/ast.rs | 58 ++- src/libsyntax/attr.rs | 330 ++++++++++++------ src/libsyntax/config.rs | 37 +- src/libsyntax/diagnostic_list.rs | 18 + src/libsyntax/ext/build.rs | 13 +- src/libsyntax/feature_gate.rs | 51 ++- src/libsyntax/fold.rs | 19 +- src/libsyntax/parse/attr.rs | 64 +++- src/libsyntax/print/pprust.rs | 19 +- src/libsyntax/test.rs | 9 +- src/libsyntax_ext/deriving/cmp/eq.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 2 +- src/libsyntax_ext/deriving/mod.rs | 6 +- .../auxiliary/macro_crate_test.rs | 17 +- src/test/compile-fail/E0565-1.rs | 17 + src/test/compile-fail/E0565.rs | 17 + src/test/compile-fail/attr-literals.rs | 33 ++ src/test/compile-fail/gated-attr-literals.rs | 44 +++ src/test/parse-fail/suffixed-literal-meta.rs | 25 ++ .../attr-literals.rs} | 16 +- .../auxiliary/custom_derive_plugin.rs | 1 - .../auxiliary/custom_derive_plugin_attr.rs | 2 +- .../auxiliary/macro_crate_test.rs | 103 +++++- .../auxiliary/plugin_args.rs | 4 +- .../macro-crate-multi-decorator-literals.rs | 58 +++ 45 files changed, 942 insertions(+), 373 deletions(-) create mode 100644 src/test/compile-fail/E0565-1.rs create mode 100644 src/test/compile-fail/E0565.rs create mode 100644 src/test/compile-fail/attr-literals.rs create mode 100644 src/test/compile-fail/gated-attr-literals.rs create mode 100644 src/test/parse-fail/suffixed-literal-meta.rs rename src/test/{parse-fail/non-str-meta.rs => pretty/attr-literals.rs} (66%) create mode 100644 src/test/run-pass-fulldeps/macro-crate-multi-decorator-literals.rs diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index a1c04dfcab5e6..350b9fd88f6e7 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -11,7 +11,7 @@ use session::Session; use syntax::ast; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{AttrNestedMetaItemMethods, AttrMetaMethods}; use syntax::visit; use syntax::visit::Visitor; @@ -52,18 +52,22 @@ impl<'a> CheckAttrVisitor<'a> { return; } }; + for word in words { - let word: &str = &word.name(); - let message = match word { + let name = match word.name() { + Some(word) => word, + None => continue, + }; + + let message = match &*name { "C" => { if target != Target::Struct && target != Target::Enum { - "attribute should be applied to struct or enum" + "attribute should be applied to struct or enum" } else { continue } } - "packed" | - "simd" => { + "packed" | "simd" => { if target != Target::Struct { "attribute should be applied to struct" } else { @@ -74,13 +78,14 @@ impl<'a> CheckAttrVisitor<'a> { "i32" | "u32" | "i64" | "u64" | "isize" | "usize" => { if target != Target::Enum { - "attribute should be applied to enum" + "attribute should be applied to enum" } else { continue } } _ => continue, }; + span_err!(self.sess, attr.span, E0517, "{}", message); } } diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs index 0edfd16bdfd1b..99bd22cc87b19 100644 --- a/src/librustc/hir/fold.rs +++ b/src/librustc/hir/fold.rs @@ -12,8 +12,8 @@ //! and returns a piece of the same type. use hir::*; -use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, Attribute, Attribute_, MetaItem}; -use syntax::ast::MetaItemKind; +use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, Attribute, Attribute_}; +use syntax::ast::{NestedMetaItem, NestedMetaItemKind, MetaItem, MetaItemKind}; use hir; use syntax_pos::Span; use syntax::codemap::{respan, Spanned}; @@ -38,6 +38,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) -> P { noop_fold_meta_item(meta_item, self) } @@ -486,13 +490,26 @@ pub fn noop_fold_attribute(at: Attribute, fld: &mut T) -> Option(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(mi: P, fld: &mut T) -> P { 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), }, diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 29bcc1257fd31..bccd217352b70 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -38,7 +38,7 @@ use util::nodemap::FnvHashMap; use std::cmp; use std::default::Default as StdDefault; use std::mem; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax::parse::token::InternedString; use syntax::ast; use syntax_pos::Span; @@ -372,12 +372,10 @@ pub fn gather_attr(attr: &ast::Attribute) return out; }; - for meta in metas { - out.push(if meta.is_word() { - Ok((meta.name().clone(), level, meta.span)) - } else { - Err(meta.span) - }); + for li in metas { + out.push(li.word().map_or(Err(li.span), |word| { + Ok((word.name().clone(), level, word.span)) + })); } out diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index dbee0ea9b00e9..55c6a4de9df50 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -11,7 +11,7 @@ use borrowck::BorrowckCtxt; use syntax::ast::{self, MetaItem}; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax::ptr::P; use syntax_pos::{Span, DUMMY_SP}; @@ -43,8 +43,9 @@ fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option return Some(mi.clone()), + _ => continue } } } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 4e87c931cc19d..1f3f823d0b8ab 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -655,17 +655,19 @@ impl RustcDefaultCalls { if !allow_unstable_cfg && GatedCfg::gate(&*cfg).is_some() { continue; } + if cfg.is_word() { println!("{}", cfg.name()); - } else if cfg.is_value_str() { - if let Some(s) = cfg.value_str() { - println!("{}=\"{}\"", cfg.name(), s); - } + } else if let Some(s) = cfg.value_str() { + println!("{}=\"{}\"", cfg.name(), s); } else if cfg.is_meta_item_list() { // Right now there are not and should not be any // MetaItemKind::List items in the configuration returned by // `build_configuration`. - panic!("MetaItemKind::List encountered in default cfg") + panic!("Found an unexpected list in cfg attribute '{}'!", cfg.name()) + } else { + // There also shouldn't be literals. + panic!("Found an unexpected literal in cfg attribute '{}'!", cfg.name()) } } } diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 420c88e89be0d..482b351481c4e 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -56,7 +56,7 @@ use std::env; use std::fs::File; use std::io::Write; use syntax::ast; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{AttrNestedMetaItemMethods, AttrMetaMethods}; use syntax::parse::token::InternedString; use syntax_pos::Span; @@ -116,14 +116,18 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { for attr in self.tcx.get_attrs(def_id).iter() { if attr.check_name(IF_THIS_CHANGED) { let mut id = None; - for meta_item in attr.meta_item_list().unwrap_or_default() { - if meta_item.is_word() && id.is_none() { - id = Some(meta_item.name().clone()); - } else { - // FIXME better-encapsulate meta_item (don't directly access `node`) - span_bug!(meta_item.span(), "unexpected meta-item {:?}", meta_item.node) + for list_item in attr.meta_item_list().unwrap_or_default() { + match list_item.word() { + Some(word) if id.is_none() => { + id = Some(word.name().clone()) + }, + _ => { + // FIXME better-encapsulate meta_item (don't directly access `node`) + span_bug!(list_item.span(), "unexpected list-item {:?}", list_item.node) + } } } + let id = id.unwrap_or(InternedString::new(ID)); self.if_this_changed.entry(id) .or_insert(FnvHashSet()) @@ -131,16 +135,21 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { } else if attr.check_name(THEN_THIS_WOULD_NEED) { let mut dep_node_interned = None; let mut id = None; - for meta_item in attr.meta_item_list().unwrap_or_default() { - if meta_item.is_word() && dep_node_interned.is_none() { - dep_node_interned = Some(meta_item.name().clone()); - } else if meta_item.is_word() && id.is_none() { - id = Some(meta_item.name().clone()); - } else { - // FIXME better-encapsulate meta_item (don't directly access `node`) - span_bug!(meta_item.span(), "unexpected meta-item {:?}", meta_item.node) + for list_item in attr.meta_item_list().unwrap_or_default() { + match list_item.word() { + Some(word) if dep_node_interned.is_none() => { + dep_node_interned = Some(word.name().clone()); + }, + Some(word) if id.is_none() => { + id = Some(word.name().clone()) + }, + _ => { + // FIXME better-encapsulate meta_item (don't directly access `node`) + span_bug!(list_item.span(), "unexpected meta-item {:?}", list_item.node) + } } } + let dep_node = match dep_node_interned { Some(ref n) => { match DepNode::from_label_string(&n[..], def_id) { diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 65da3a09ecca5..f0092ce04d1f6 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -31,8 +31,8 @@ use rustc::hir; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::Visitor; use rustc_data_structures::fnv::FnvHashSet; -use syntax::ast::{self, Attribute, MetaItem}; -use syntax::attr::AttrMetaMethods; +use syntax::ast::{self, Attribute, NestedMetaItem}; +use syntax::attr::{AttrNestedMetaItemMethods, AttrMetaMethods}; use syntax::parse::token::InternedString; use rustc::ty::TyCtxt; @@ -71,13 +71,17 @@ pub struct DirtyCleanVisitor<'a, 'tcx:'a> { } impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { - fn expect_associated_value(&self, item: &MetaItem) -> InternedString { + fn expect_associated_value(&self, item: &NestedMetaItem) -> InternedString { if let Some(value) = item.value_str() { value } else { - self.tcx.sess.span_fatal( - item.span, - &format!("associated value expected for `{}`", item.name())); + let msg = if let Some(name) = item.name() { + format!("associated value expected for `{}`", name) + } else { + "expected an associated value".to_string() + }; + + self.tcx.sess.span_fatal(item.span, &msg); } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index b4a2648b5dca7..9a4eec2d05b7a 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -44,8 +44,8 @@ use lint::{LintPass, LateLintPass}; use std::collections::HashSet; use syntax::{ast}; -use syntax::attr::{self, AttrMetaMethods, AttributeMethods}; -use syntax_pos::Span; +use syntax::attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods, AttributeMethods}; +use syntax_pos::{Span}; use rustc::hir::{self, PatKind}; use rustc::hir::intravisit::FnKind; @@ -317,7 +317,7 @@ impl LateLintPass for MissingDoc { let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| { attr.check_name("doc") && match attr.meta_item_list() { None => false, - Some(l) => attr::contains_name(&l[..], "hidden"), + Some(l) => attr::list_contains_name(&l[..], "hidden"), } }); self.doc_hidden_stack.push(doc_hidden); diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 57705301aab4e..44c2ffe45ccb4 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -234,10 +234,13 @@ impl LintPass for UnusedAttributes { impl LateLintPass for UnusedAttributes { fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) { + debug!("checking attribute: {:?}", attr); + // Note that check_name() marks the attribute as used if it matches. for &(ref name, ty, _) in KNOWN_ATTRIBUTES { match ty { AttributeType::Whitelisted if attr.check_name(name) => { + debug!("{:?} is Whitelisted", name); break; }, _ => () @@ -247,11 +250,13 @@ impl LateLintPass for UnusedAttributes { let plugin_attributes = cx.sess().plugin_attributes.borrow_mut(); for &(ref name, ty) in plugin_attributes.iter() { if ty == AttributeType::Whitelisted && attr.check_name(&name) { + debug!("{:?} (plugin attr) is whitelisted with ty {:?}", name, ty); break; } } if !attr::is_used(attr) { + debug!("Emitting warning for: {:?}", attr); cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute"); // Is it a builtin attribute that must be used at the crate level? let known_crate = KNOWN_ATTRIBUTES.iter().find(|&&(name, ty, _)| { @@ -275,6 +280,8 @@ impl LateLintPass for UnusedAttributes { }; cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg); } + } else { + debug!("Attr was used: {:?}", attr); } } } diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 99a3f3b00c8b0..85cf41e42a273 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -45,26 +45,13 @@ pub const tag_items_closure_kind: usize = 0x2a; pub const tag_items_closure_ty: usize = 0x2b; pub const tag_def_key: usize = 0x2c; -// GAP 0x2d 0x2e +// GAP 0x2d 0x34 pub const tag_index: usize = 0x110; // top-level only pub const tag_xref_index: usize = 0x111; // top-level only pub const tag_xref_data: usize = 0x112; // top-level only - -pub const tag_meta_item_name_value: usize = 0x2f; - -pub const tag_meta_item_name: usize = 0x30; - -pub const tag_meta_item_value: usize = 0x31; - pub const tag_attributes: usize = 0x101; // top-level only -pub const tag_attribute: usize = 0x32; - -pub const tag_meta_item_word: usize = 0x33; - -pub const tag_meta_item_list: usize = 0x34; - // The list of crates that this crate depends on pub const tag_crate_deps: usize = 0x102; // top-level only diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 46469efea6bc8..4dc3d04c4a23b 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -35,8 +35,7 @@ use syntax::ast; use syntax::abi::Abi; use syntax::codemap; use syntax::parse; -use syntax::attr; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax::parse::token::InternedString; use syntax::visit; use syntax_pos::{self, Span, mk_sp, Pos}; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index b0335258b4041..b8ed1f7bae63b 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -56,7 +56,6 @@ use syntax::parse::token; use syntax::ast; use syntax::codemap; use syntax::print::pprust; -use syntax::ptr::P; use syntax_pos::{self, Span, BytePos, NO_EXPANSION}; pub type Cmd<'a> = &'a CrateMetadata; @@ -1121,44 +1120,20 @@ pub fn get_struct_field_names(cdata: Cmd, id: DefIndex) -> Vec { })).collect() } -fn get_meta_items(md: rbml::Doc) -> Vec> { - reader::tagged_docs(md, tag_meta_item_word).map(|meta_item_doc| { - let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); - let n = token::intern_and_get_ident(nd.as_str()); - attr::mk_word_item(n) - }).chain(reader::tagged_docs(md, tag_meta_item_name_value).map(|meta_item_doc| { - let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); - let vd = reader::get_doc(meta_item_doc, tag_meta_item_value); - let n = token::intern_and_get_ident(nd.as_str()); - let v = token::intern_and_get_ident(vd.as_str()); - // FIXME (#623): Should be able to decode MetaItemKind::NameValue variants, - // but currently the encoder just drops them - attr::mk_name_value_item_str(n, v) - })).chain(reader::tagged_docs(md, tag_meta_item_list).map(|meta_item_doc| { - let nd = reader::get_doc(meta_item_doc, tag_meta_item_name); - let n = token::intern_and_get_ident(nd.as_str()); - let subitems = get_meta_items(meta_item_doc); - attr::mk_list_item(n, subitems) - })).collect() -} - fn get_attributes(md: rbml::Doc) -> Vec { - match reader::maybe_get_doc(md, tag_attributes) { - Some(attrs_d) => { - reader::tagged_docs(attrs_d, tag_attribute).map(|attr_doc| { - let is_sugared_doc = reader::doc_as_u8( - reader::get_doc(attr_doc, tag_attribute_is_sugared_doc) - ) == 1; - let meta_items = get_meta_items(attr_doc); - // Currently it's only possible to have a single meta item on - // an attribute - assert_eq!(meta_items.len(), 1); - let meta_item = meta_items.into_iter().nth(0).unwrap(); - attr::mk_doc_attr_outer(attr::mk_attr_id(), meta_item, is_sugared_doc) - }).collect() - }, - None => vec![], - } + reader::maybe_get_doc(md, tag_attributes).map_or(vec![], |attrs_doc| { + let mut decoder = reader::Decoder::new(attrs_doc); + let mut attrs: Vec = decoder.read_opaque(|opaque_decoder, _| { + Decodable::decode(opaque_decoder) + }).unwrap(); + + // Need new unique IDs: old thread-local IDs won't map to new threads. + for attr in attrs.iter_mut() { + attr.node.id = attr::mk_attr_id(); + } + + attrs + }) } fn list_crate_attributes(md: rbml::Doc, hash: &Svh, diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 9a668b69b2eeb..ef8253713f5a1 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -41,7 +41,7 @@ use std::io::{Cursor, SeekFrom}; use std::rc::Rc; use std::u32; use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum}; -use syntax::attr::{self,AttrMetaMethods,AttributeMethods}; +use syntax::attr; use errors::Handler; use syntax; use syntax_pos::BytePos; @@ -1412,40 +1412,11 @@ fn encode_item_index(rbml_w: &mut Encoder, index: IndexData) { rbml_w.end_tag(); } -fn encode_meta_item(rbml_w: &mut Encoder, mi: &ast::MetaItem) { - if mi.is_word() { - let name = mi.name(); - rbml_w.start_tag(tag_meta_item_word); - rbml_w.wr_tagged_str(tag_meta_item_name, &name); - rbml_w.end_tag(); - } else if mi.is_value_str() { - let name = mi.name(); - /* FIXME (#623): support other literal kinds */ - let value = mi.value_str().unwrap(); - rbml_w.start_tag(tag_meta_item_name_value); - rbml_w.wr_tagged_str(tag_meta_item_name, &name); - rbml_w.wr_tagged_str(tag_meta_item_value, &value); - rbml_w.end_tag(); - } else { // it must be a list - let name = mi.name(); - let items = mi.meta_item_list().unwrap(); - rbml_w.start_tag(tag_meta_item_list); - rbml_w.wr_tagged_str(tag_meta_item_name, &name); - for inner_item in items { - encode_meta_item(rbml_w, &inner_item); - } - rbml_w.end_tag(); - } -} - fn encode_attributes(rbml_w: &mut Encoder, attrs: &[ast::Attribute]) { rbml_w.start_tag(tag_attributes); - for attr in attrs { - rbml_w.start_tag(tag_attribute); - rbml_w.wr_tagged_u8(tag_attribute_is_sugared_doc, attr.node.is_sugared_doc as u8); - encode_meta_item(rbml_w, attr.meta()); - rbml_w.end_tag(); - } + rbml_w.emit_opaque(|opaque_encoder| { + attrs.encode(opaque_encoder) + }).unwrap(); rbml_w.end_tag(); } diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs index b2a2dcf90fa4b..ec0c9f455cd0c 100644 --- a/src/librustc_metadata/macro_import.rs +++ b/src/librustc_metadata/macro_import.rs @@ -18,8 +18,7 @@ use rustc::session::Session; use std::collections::{HashSet, HashMap}; use syntax::parse::token; use syntax::ast; -use syntax::attr; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{self, AttrNestedMetaItemMethods, AttrMetaMethods}; use syntax::ext; use syntax_pos::Span; @@ -64,8 +63,8 @@ impl<'a> ext::base::MacroLoader for MacroLoader<'a> { } if let (Some(sel), Some(names)) = (import.as_mut(), names) { for attr in names { - if attr.is_word() { - sel.insert(attr.name().clone(), attr.span()); + if let Some(word) = attr.word() { + sel.insert(word.name().clone(), attr.span()); } else { span_err!(self.sess, attr.span(), E0466, "bad macro import"); } @@ -82,8 +81,8 @@ impl<'a> ext::base::MacroLoader for MacroLoader<'a> { }; for attr in names { - if attr.is_word() { - reexport.insert(attr.name().clone(), attr.span()); + if let Some(word) = attr.word() { + reexport.insert(word.name().clone(), attr.span()); } else { call_bad_macro_reexport(self.sess, attr.span()); } diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index fb68eae96476f..5a8d2e58c558b 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -20,8 +20,7 @@ use std::env; use std::mem; use std::path::PathBuf; use syntax::ast; -use syntax::ptr::P; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax_pos::{Span, COMMAND_LINE_SP}; /// Pointer to a registrar function. @@ -30,7 +29,7 @@ pub type PluginRegistrarFun = pub struct PluginRegistrar { pub fun: PluginRegistrarFun, - pub args: Vec>, + pub args: Vec, } struct PluginLoader<'a> { @@ -69,13 +68,14 @@ pub fn load_plugins(sess: &Session, }; for plugin in plugins { - if plugin.value_str().is_some() { - call_malformed_plugin_attribute(sess, attr.span); - continue; + // plugins must have a name and can't be key = value + match plugin.name() { + Some(ref name) if !plugin.is_value_str() => { + let args = plugin.meta_item_list().map(ToOwned::to_owned); + loader.load_plugin(plugin.span, name, args.unwrap_or_default()); + }, + _ => call_malformed_plugin_attribute(sess, attr.span), } - - let args = plugin.meta_item_list().map(ToOwned::to_owned).unwrap_or_default(); - loader.load_plugin(plugin.span, &plugin.name(), args); } } } @@ -102,7 +102,7 @@ impl<'a> PluginLoader<'a> { } } - fn load_plugin(&mut self, span: Span, name: &str, args: Vec>) { + fn load_plugin(&mut self, span: Span, name: &str, args: Vec) { let registrar = self.reader.find_plugin_registrar(span, name); if let Some((lib, svh, index)) = registrar { diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index 54fa0197de4fe..5ae6584aed425 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -19,7 +19,6 @@ use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT}; use syntax::ext::base::{IdentTT, MultiModifier, MultiDecorator}; use syntax::ext::base::{MacroExpanderFn, MacroRulesTT}; use syntax::parse::token; -use syntax::ptr::P; use syntax::ast; use syntax::feature_gate::AttributeType; use syntax_pos::Span; @@ -41,7 +40,7 @@ pub struct Registry<'a> { pub sess: &'a Session, #[doc(hidden)] - pub args_hidden: Option>>, + pub args_hidden: Option>, #[doc(hidden)] pub krate_span: Span, @@ -95,7 +94,7 @@ impl<'a> Registry<'a> { /// /// Returns empty slice in case the plugin was loaded /// with `--extra-plugins` - pub fn args<'b>(&'b self) -> &'b [P] { + pub fn args<'b>(&'b self) -> &'b [ast::NestedMetaItem] { self.args_hidden.as_ref().map(|v| &v[..]).unwrap_or(&[]) } diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs index e0532e7476f51..e2633c829761f 100644 --- a/src/librustc_trans/assert_module_sources.rs +++ b/src/librustc_trans/assert_module_sources.rs @@ -29,7 +29,7 @@ use rustc::ty::TyCtxt; use syntax::ast; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax::parse::token::InternedString; use {ModuleSource, ModuleTranslation}; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e2e655ce38bcc..02fa073dd5523 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -26,10 +26,11 @@ pub use self::Visibility::*; use syntax::abi::Abi; use syntax::ast; use syntax::attr; -use syntax::attr::{AttributeMethods, AttrMetaMethods}; +use syntax::attr::{AttributeMethods, AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax::codemap::Spanned; use syntax::parse::token::{self, InternedString, keywords}; use syntax::ptr::P; +use syntax::print::pprust as syntax_pprust; use syntax_pos::{self, DUMMY_SP, Pos}; use rustc_trans::back::link; @@ -501,11 +502,24 @@ impl Attributes for [Attribute] { } } +/// This is a flattened version of the AST's Attribute + MetaItem. #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] pub enum Attribute { Word(String), List(String, Vec), - NameValue(String, String) + NameValue(String, String), + Literal(String), +} + +impl Clean for ast::NestedMetaItem { + fn clean(&self, cx: &DocContext) -> Attribute { + if let Some(mi) = self.meta_item() { + mi.clean(cx) + } else { // must be a literal + let lit = self.literal().unwrap(); + Literal(syntax_pprust::lit_to_string(lit)) + } + } } impl Clean for ast::MetaItem { @@ -528,12 +542,28 @@ impl Clean for ast::Attribute { } // This is a rough approximation that gets us what we want. -impl attr::AttrMetaMethods for Attribute { - fn name(&self) -> InternedString { +impl attr::AttrNestedMetaItemMethods for Attribute { + fn check_name(&self, name: &str) -> bool { + self.name().map_or(false, |mi_name| &*mi_name == name) + } + + fn literal(&self) -> Option<&ast::Lit> { None } + + fn is_literal(&self) -> bool { + match *self { + Literal(..) => true, + _ => false, + } + } + + fn meta_item(&self) -> Option<&P> { None } + + fn name(&self) -> Option { match *self { Word(ref n) | List(ref n, _) | NameValue(ref n, _) => { - token::intern_and_get_ident(n) - } + Some(token::intern_and_get_ident(n)) + }, + _ => None } } @@ -545,7 +575,8 @@ impl attr::AttrMetaMethods for Attribute { _ => None, } } - fn meta_item_list<'a>(&'a self) -> Option<&'a [P]> { None } + + fn word(&self) -> Option<&P> { None } fn is_word(&self) -> bool { match *self { @@ -554,12 +585,7 @@ impl attr::AttrMetaMethods for Attribute { } } - fn is_value_str(&self) -> bool { - match *self { - NameValue(..) => true, - _ => false, - } - } + fn meta_item_list<'a>(&'a self) -> Option<&'a [ast::NestedMetaItem]> { None } fn is_meta_item_list(&self) -> bool { match *self { @@ -2535,8 +2561,8 @@ impl Clean> for doctree::Import { // Don't inline doc(hidden) imports so they can be stripped at a later stage. let denied = self.vis != hir::Public || self.attrs.iter().any(|a| { &a.name()[..] == "doc" && match a.meta_item_list() { - Some(l) => attr::contains_name(l, "no_inline") || - attr::contains_name(l, "hidden"), + Some(l) => attr::list_contains_name(l, "no_inline") || + attr::list_contains_name(l, "hidden"), None => false, } }); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 7d1dbbe5dc07d..23a047f922f9d 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -141,6 +141,7 @@ pub fn run(input: &str, // Look for #![doc(test(no_crate_inject))], used by crates in the std facade fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions { use syntax::attr::AttrMetaMethods; + use syntax::attr::AttrNestedMetaItemMethods; use syntax::print::pprust; let mut opts = TestOptions { @@ -162,7 +163,7 @@ fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions { if attr.check_name("attr") { if let Some(l) = attr.meta_item_list() { for item in l { - opts.attrs.push(pprust::meta_item_to_string(item)); + opts.attrs.push(pprust::meta_list_item_to_string(item)); } } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 0334c5ef5c4f4..4e3a81b1baeac 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -17,7 +17,7 @@ use std::mem; use syntax::abi; use syntax::ast; use syntax::attr; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax_pos::Span; use rustc::hir::map as hir_map; @@ -333,8 +333,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let node = if item.vis == hir::Public { let please_inline = item.attrs.iter().any(|item| { match item.meta_item_list() { - Some(list) if &item.name()[..] == "doc" => { - list.iter().any(|i| &i.name()[..] == "inline") + Some(list) if item.check_name("doc") => { + list.iter().any(|i| i.check_name("inline")) } _ => false, } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f8a5cb0b04a8e..63fd2e7686fdf 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -439,6 +439,22 @@ pub struct Crate { pub exported_macros: Vec, } +/// A spanned compile-time attribute list item. +pub type NestedMetaItem = Spanned; + +/// 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), + /// A literal. + /// + /// E.g. "foo", 64, true + Literal(Lit), +} + /// A spanned compile-time attribute item. /// /// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]` @@ -456,7 +472,7 @@ pub enum MetaItemKind { /// List meta item. /// /// E.g. `derive(..)` as in `#[derive(..)]` - List(InternedString, Vec>), + List(InternedString, Vec), /// Name value meta item. /// /// E.g. `feature = "foo"` as in `#[feature = "foo"]` @@ -472,19 +488,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 +1123,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 diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index b622f6861b383..4897425f2c06c 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,6 +81,93 @@ pub fn is_used(attr: &Attribute) -> bool { }) } +pub trait AttrNestedMetaItemMethods { + /// Returns true if this list item is a MetaItem with a name of `name`. + 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 + fn name(&self) -> Option { + self.meta_item().and_then(|meta_item| Some(meta_item.name())) + } + + /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem. + fn meta_item(&self) -> Option<&P>; + + /// Returns the Lit if self is a NestedMetaItemKind::Literal. + fn literal(&self) -> Option<&Lit>; + + /// Gets the string value if self is a MetaItem and the MetaItem is a + /// MetaItemKind::NameValue variant containing a string, otherwise None. + fn value_str(&self) -> Option { + self.meta_item().and_then(|meta_item| meta_item.value_str()) + } + + /// Returns a MetaItem if self is a MetaItem with Kind Word. + fn word(&self) -> Option<&P> { + self.meta_item().and_then(|meta_item| if meta_item.is_word() { + Some(meta_item) + } else { + None + }) + } + + /// Gets a list of inner meta items from a list MetaItem type. + fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { + self.meta_item().and_then(|meta_item| meta_item.meta_item_list()) + } + + /// Returns `true` if the variant is MetaItem. + fn is_meta_item(&self) -> bool { + self.meta_item().is_some() + } + + /// Returns `true` if the variant is Literal. + fn is_literal(&self) -> bool { + self.literal().is_some() + } + + /// Returns `true` if self is a MetaItem and the meta item is a word. + fn is_word(&self) -> bool { + self.word().is_some() + } + + /// Returns `true` if self is a MetaItem and the meta item is a ValueString. + fn is_value_str(&self) -> bool { + self.value_str().is_some() + } + + /// Returns `true` if self is a MetaItem and the meta item is a list. + fn is_meta_item_list(&self) -> bool { + self.meta_item_list().is_some() + } + + /// Returns the Span for `self`. + fn span(&self) -> Span; +} + +impl AttrNestedMetaItemMethods for NestedMetaItem { + fn meta_item(&self) -> Option<&P> { + match self.node { + NestedMetaItemKind::MetaItem(ref item) => Some(&item), + _ => None + } + } + + fn literal(&self) -> Option<&Lit> { + match self.node { + NestedMetaItemKind::Literal(ref lit) => Some(&lit), + _ => None + } + } + + fn span(&self) -> Span { + self.span + } +} + pub trait AttrMetaMethods { fn check_name(&self, name: &str) -> bool { name == &self.name()[..] @@ -89,8 +180,9 @@ pub trait AttrMetaMethods { /// Gets the string value if self is a MetaItemKind::NameValue variant /// containing a string, otherwise None. fn value_str(&self) -> Option; + /// Gets a list of inner meta items from a list MetaItem type. - fn meta_item_list(&self) -> Option<&[P]>; + fn meta_item_list(&self) -> Option<&[NestedMetaItem]>; /// Indicates if the attribute is a Word. fn is_word(&self) -> bool; @@ -116,11 +208,14 @@ impl AttrMetaMethods for Attribute { } matches } + fn name(&self) -> InternedString { self.meta().name() } + fn value_str(&self) -> Option { self.meta().value_str() } - fn meta_item_list(&self) -> Option<&[P]> { + + fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { self.meta().meta_item_list() } @@ -150,7 +245,7 @@ impl AttrMetaMethods for MetaItem { } } - fn meta_item_list(&self) -> Option<&[P]> { + fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { match self.node { MetaItemKind::List(_, ref l) => Some(&l[..]), _ => None @@ -171,7 +266,7 @@ impl AttrMetaMethods for MetaItem { impl AttrMetaMethods for P { fn name(&self) -> InternedString { (**self).name() } fn value_str(&self) -> Option { (**self).value_str() } - fn meta_item_list(&self) -> Option<&[P]> { + fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { (**self).meta_item_list() } fn is_word(&self) -> bool { (**self).is_word() } @@ -229,10 +324,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 { +pub fn mk_list_item(name: InternedString, items: Vec) -> P { 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 { mk_spanned_word_item(DUMMY_SP, name) } @@ -242,7 +341,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>) +pub fn mk_spanned_list_item(sp: Span, name: InternedString, items: Vec) -> P { P(respan(sp, MetaItemKind::List(name, items))) } @@ -332,6 +431,14 @@ pub fn contains(haystack: &[P], needle: &MetaItem) -> bool { }) } +pub fn list_contains_name(items: &[AM], 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(metas: &[AM], name: &str) -> bool { debug!("attr::contains_name (name={})", name); metas.iter().any(|item| { @@ -357,27 +464,6 @@ pub fn last_meta_item_value_str_by_name(items: &[P], name: &str) /* Higher-level applications */ -pub fn sort_meta_items(items: Vec>) -> Vec> { - // 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::)>>(); - - 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 { first_attr_value_str_by_name(attrs, "crate_name") } @@ -427,14 +513,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 +540,44 @@ pub fn requests_inline(attrs: &[Attribute]) -> bool { /// Tests if a cfg-pattern matches the cfg set pub fn cfg_matches(cfgs: &[P], 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 +661,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 +704,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 +759,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 +858,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 +920,36 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec 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 a825cf866a878..4663143f4b1f8 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::{AttrMetaMethods, AttrNestedMetaItemMethods, 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(, )]`"; + 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) }) } diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 010b1d638e63c..9110e989a8a14 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/build.rs b/src/libsyntax/ext/build.rs index 5d6429f7bdfff..1d3939df6fb82 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -277,10 +277,13 @@ pub trait AstBuilder { fn attribute(&self, sp: Span, mi: P) -> ast::Attribute; fn meta_word(&self, sp: Span, w: InternedString) -> P; + + fn meta_list_item_word(&self, sp: Span, w: InternedString) -> ast::NestedMetaItem; + fn meta_list(&self, sp: Span, name: InternedString, - mis: Vec> ) + mis: Vec ) -> P; fn meta_name_value(&self, sp: Span, @@ -1141,10 +1144,16 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn meta_word(&self, sp: Span, w: InternedString) -> P { attr::mk_spanned_word_item(sp, w) } - fn meta_list(&self, sp: Span, name: InternedString, mis: Vec>) + + 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) -> P { attr::mk_spanned_list_item(sp, name, mis) } + fn meta_name_value(&self, sp: Span, name: InternedString, value: ast::LitKind) -> P { attr::mk_spanned_name_value_item(sp, name, respan(sp, value)) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d746f8e21141f..df1d5c4d9ca2f 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -26,10 +26,8 @@ use self::AttributeType::*; use self::AttributeGate::*; use abi::Abi; -use ast::{NodeId, PatKind}; -use ast; -use attr; -use attr::AttrMetaMethods; +use ast::{self, NodeId, PatKind}; +use attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods}; use codemap::CodeMap; use syntax_pos::Span; use errors::Handler; @@ -283,7 +281,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! ( @@ -831,11 +832,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) { @@ -895,7 +919,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"); @@ -1155,13 +1179,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 b257ab98987dc..b361a856dbe2c 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) -> P { noop_fold_meta_item(meta_item, self) } @@ -513,12 +517,25 @@ pub fn noop_fold_mac(Spanned {node, span}: Mac, fld: &mut T) -> Mac { } } +pub fn noop_fold_meta_list_item(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(mi: P, fld: &mut T) -> P { 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) }, diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 2ae3236cd5aa7..27dd055cd3ae7 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> { 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>> { + /// 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> { 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/print/pprust.rs b/src/libsyntax/print/pprust.rs index a77c678248b56..562cc896aef01 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -120,7 +120,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 +406,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 +768,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 +795,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()); } } diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index faf6a17a15045..ce917f248e1ef 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -19,8 +19,7 @@ use std::iter; use std::slice; use std::mem; use std::vec; -use attr::AttrMetaMethods; -use attr; +use attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax_pos::{self, DUMMY_SP, NO_EXPANSION, Span, FileMap, BytePos}; use std::rc::Rc; @@ -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) } diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs index 2ab0f0ff54669..2515435abeb9e 100644 --- a/src/libsyntax_ext/deriving/cmp/eq.rs +++ b/src/libsyntax_ext/deriving/cmp/eq.rs @@ -40,7 +40,7 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, } let inline = cx.meta_word(span, InternedString::new("inline")); - let hidden = cx.meta_word(span, InternedString::new("hidden")); + let hidden = cx.meta_list_item_word(span, InternedString::new("hidden")); let doc = cx.meta_list(span, InternedString::new("doc"), vec![hidden]); let attrs = vec![cx.attribute(span, inline), cx.attribute(span, doc)]; let trait_def = TraitDef { diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index cd49e7ec9d2c6..bae40ddf45c9f 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -623,7 +623,7 @@ impl<'a> TraitDef<'a> { let unused_qual = cx.attribute(self.span, cx.meta_list(self.span, InternedString::new("allow"), - vec![cx.meta_word(self.span, + vec![cx.meta_list_item_word(self.span, InternedString::new("unused_qualifications"))])); let mut a = vec![attr, unused_qual]; a.extend(self.attributes.iter().cloned()); diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index aee86b246b985..ffc1bfd6db8cd 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -11,7 +11,7 @@ //! The compiler code necessary to implement the `#[derive]` extensions. use syntax::ast::{self, MetaItem}; -use syntax::attr::AttrMetaMethods; +use syntax::attr::{AttrNestedMetaItemMethods, AttrMetaMethods}; use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv}; use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier}; use syntax::ext::build::AstBuilder; @@ -98,8 +98,8 @@ fn expand_derive(cx: &mut ExtCtxt, let mut eq_span = None; for titem in traits.iter().rev() { - let tname = if titem.is_word() { - titem.name() + let tname = if let Some(word) = titem.word() { + word.name() } else { cx.span_err(titem.span, "malformed `derive` entry"); continue; diff --git a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs index a6bc9db199c8b..6db10eeae769b 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs @@ -17,7 +17,8 @@ extern crate syntax_pos; extern crate rustc; extern crate rustc_plugin; -use syntax::ast::{self, Item, MetaItem, ImplItem, TraitItem, ItemKind}; +use syntax::ast::{self, Item, MetaItem, ItemKind}; +use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax::ext::base::*; use syntax::parse::{self, token}; use syntax::ptr::P; @@ -62,8 +63,8 @@ fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree]) } fn expand_into_foo_multi(cx: &mut ExtCtxt, - sp: Span, - attr: &MetaItem, + _sp: Span, + _attr: &MetaItem, it: Annotatable) -> Annotatable { match it { Annotatable::Item(it) => { @@ -72,7 +73,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt, ..(*quote_item!(cx, enum Foo2 { Bar2, Baz2 }).unwrap()).clone() })) } - Annotatable::ImplItem(it) => { + Annotatable::ImplItem(_) => { quote_item!(cx, impl X { fn foo(&self) -> i32 { 42 } }).unwrap().and_then(|i| { match i.node { ItemKind::Impl(_, _, _, _, _, mut items) => { @@ -82,7 +83,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt, } }) } - Annotatable::TraitItem(it) => { + Annotatable::TraitItem(_) => { quote_item!(cx, trait X { fn foo(&self) -> i32 { 0 } }).unwrap().and_then(|i| { match i.node { ItemKind::Trait(_, _, _, mut items) => { @@ -97,15 +98,15 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt, // Create a duplicate of the annotatable, based on the MetaItem fn expand_duplicate(cx: &mut ExtCtxt, - sp: Span, + _sp: Span, mi: &MetaItem, it: &Annotatable, push: &mut FnMut(Annotatable)) { let copy_name = match mi.node { ast::MetaItemKind::List(_, ref xs) => { - if let ast::MetaItemKind::Word(ref w) = xs[0].node { - token::str_to_ident(&w) + if let Some(word) = xs[0].word() { + token::str_to_ident(&word.name()) } else { cx.span_err(mi.span, "Expected word"); return; diff --git a/src/test/compile-fail/E0565-1.rs b/src/test/compile-fail/E0565-1.rs new file mode 100644 index 0000000000000..d3e68c7c0daf8 --- /dev/null +++ b/src/test/compile-fail/E0565-1.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(attr_literals)] + +// deprecated doesn't currently support literals +#[deprecated("since")] //~ ERROR E0565 +fn f() { } + +fn main() { } diff --git a/src/test/compile-fail/E0565.rs b/src/test/compile-fail/E0565.rs new file mode 100644 index 0000000000000..b2d369223e7da --- /dev/null +++ b/src/test/compile-fail/E0565.rs @@ -0,0 +1,17 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(attr_literals)] + +// repr currently doesn't support literals +#[repr("C")] //~ ERROR E0565 +struct A { } + +fn main() { } diff --git a/src/test/compile-fail/attr-literals.rs b/src/test/compile-fail/attr-literals.rs new file mode 100644 index 0000000000000..b54288035175d --- /dev/null +++ b/src/test/compile-fail/attr-literals.rs @@ -0,0 +1,33 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that literals in attributes parse just fine. + +#![feature(rustc_attrs, attr_literals)] +#![allow(dead_code)] +#![allow(unused_variables)] + +#[fake_attr] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(100)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(1, 2, 3)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr("hello")] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(name = "hello")] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(1, "hi", key = 12, true, false)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(key = "hello", val = 10)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(key("hello"), val(10))] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(enabled = true, disabled = false)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(true)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(pi = 3.14159)] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(b"hi")] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_doc(r"doc")] //~ ERROR attribute `fake_doc` is currently unknown +struct Q { } + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/gated-attr-literals.rs b/src/test/compile-fail/gated-attr-literals.rs new file mode 100644 index 0000000000000..f3132d5593e62 --- /dev/null +++ b/src/test/compile-fail/gated-attr-literals.rs @@ -0,0 +1,44 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that literals in attributes don't parse without the feature gate. + +#![feature(rustc_attrs)] +#![allow(dead_code)] +#![allow(unused_variables)] + +#[fake_attr] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(100)] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR non-string literals in attributes +#[fake_attr(1, 2, 3)] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR non-string literals in attributes +#[fake_attr("hello")] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR string literals in top-level positions, are experimental +#[fake_attr(name = "hello")] //~ ERROR attribute `fake_attr` is currently unknown +#[fake_attr(1, "hi", key = 12, true, false)] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR non-string literals in attributes, or string literals in top-level positions +#[fake_attr(key = "hello", val = 10)] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR non-string literals in attributes +#[fake_attr(key("hello"), val(10))] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR non-string literals in attributes, or string literals in top-level positions +#[fake_attr(enabled = true, disabled = false)] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR non-string literals in attributes +#[fake_attr(true)] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR non-string literals in attributes +#[fake_attr(pi = 3.14159)] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR non-string literals in attributes +#[fake_attr(b"hi")] //~ ERROR attribute `fake_attr` is currently unknown + //~^ ERROR string literals in top-level positions, are experimental +#[fake_doc(r"doc")] //~ ERROR attribute `fake_doc` is currently unknown + //~^ ERROR string literals in top-level positions, are experimental +struct Q { } + +#[rustc_error] +fn main() { } diff --git a/src/test/parse-fail/suffixed-literal-meta.rs b/src/test/parse-fail/suffixed-literal-meta.rs new file mode 100644 index 0000000000000..0e2840c69d364 --- /dev/null +++ b/src/test/parse-fail/suffixed-literal-meta.rs @@ -0,0 +1,25 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +#[foo = 1usize] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1u8] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1u16] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1u32] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1u64] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1isize] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1i8] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1i16] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1i32] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1i64] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1.0f32] //~ ERROR: suffixed literals are not allowed in attributes +#[foo = 1.0f64] //~ ERROR: suffixed literals are not allowed in attributes +fn main() { } diff --git a/src/test/parse-fail/non-str-meta.rs b/src/test/pretty/attr-literals.rs similarity index 66% rename from src/test/parse-fail/non-str-meta.rs rename to src/test/pretty/attr-literals.rs index 3e2e69d2814e5..ba8c580cb0a01 100644 --- a/src/test/parse-fail/non-str-meta.rs +++ b/src/test/pretty/attr-literals.rs @@ -8,10 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only +// pp-exact +// Tests literals in attributes. -// Issue #623 - non-string meta items are not serialized correctly; -// for now just forbid them +#![feature(custom_attribute, attr_literals)] -#[foo = 1] //~ ERROR: non-string literals are not allowed in meta-items -fn main() { } +fn main() { + #![hello("hi", 1, 2, 1.012, pi = 3.14, bye, name("John"))] + #[align = 8] + fn f() { } + + #[vec(1, 2, 3)] + fn g() { } +} diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs index 42135703b75a4..274e430bbea74 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs @@ -24,7 +24,6 @@ use syntax::ast; use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable}; use syntax::ext::build::AstBuilder; use syntax::parse::token; -use syntax::ptr::P; use syntax_ext::deriving::generic::{cs_fold, TraitDef, MethodDef, combine_substructure}; use syntax_ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self}; use syntax_pos::Span; diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs index eeecd0b24e29e..882e90b2d6c15 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs @@ -26,7 +26,7 @@ use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable}; use syntax::ext::build::AstBuilder; use syntax::parse::token; use syntax::ptr::P; -use syntax_ext::deriving::generic::{cs_fold, TraitDef, MethodDef, combine_substructure}; +use syntax_ext::deriving::generic::{TraitDef, MethodDef, combine_substructure}; use syntax_ext::deriving::generic::{Substructure, Struct, EnumMatching}; use syntax_ext::deriving::generic::ty::{Literal, LifetimeBounds, Path, borrowed_explicit_self}; use syntax_pos::Span; diff --git a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs index 3f50811f826e0..e37cd89f29991 100644 --- a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs @@ -17,8 +17,11 @@ extern crate rustc; extern crate rustc_plugin; extern crate syntax_pos; -use syntax::ast::{self, Item, MetaItem, ImplItem, TraitItem, ItemKind}; +use syntax::ast::{self, Item, MetaItem, ItemKind}; +use syntax::codemap::DUMMY_SP; +use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax::ext::base::*; +use syntax::ext::quote::rt::ToTokens; use syntax::parse::{self, token}; use syntax::ptr::P; use syntax::tokenstream::TokenTree; @@ -41,10 +44,13 @@ pub fn plugin_registrar(reg: &mut Registry) { token::intern("duplicate"), // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. MultiDecorator(Box::new(expand_duplicate))); + reg.register_syntax_extension( + token::intern("caller"), + // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. + MultiDecorator(Box::new(expand_caller))); } -fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) - -> Box { +fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box { if !tts.is_empty() { cx.span_fatal(sp, "make_a_1 takes no arguments"); } @@ -52,19 +58,18 @@ fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) } // See Issue #15750 -fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree]) - -> Box { +fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree]) -> Box { // Parse an expression and emit it unchanged. - let mut parser = parse::new_parser_from_tts(cx.parse_sess(), - cx.cfg(), tts.to_vec()); + let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.to_vec()); let expr = parser.parse_expr().unwrap(); MacEager::expr(quote_expr!(&mut *cx, $expr)) } fn expand_into_foo_multi(cx: &mut ExtCtxt, - sp: Span, - attr: &MetaItem, - it: Annotatable) -> Vec { + _sp: Span, + _attr: &MetaItem, + it: Annotatable) + -> Vec { match it { Annotatable::Item(it) => vec![ Annotatable::Item(P(Item { @@ -74,7 +79,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt, Annotatable::Item(quote_item!(cx, enum Foo3 { Bar }).unwrap()), Annotatable::Item(quote_item!(cx, #[cfg(any())] fn foo2() {}).unwrap()), ], - Annotatable::ImplItem(it) => vec![ + Annotatable::ImplItem(_it) => vec![ quote_item!(cx, impl X { fn foo(&self) -> i32 { 42 } }).unwrap().and_then(|i| { match i.node { ItemKind::Impl(_, _, _, _, _, mut items) => { @@ -84,7 +89,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt, } }) ], - Annotatable::TraitItem(it) => vec![ + Annotatable::TraitItem(_it) => vec![ quote_item!(cx, trait X { fn foo(&self) -> i32 { 0 } }).unwrap().and_then(|i| { match i.node { ItemKind::Trait(_, _, _, mut items) => { @@ -99,15 +104,14 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt, // Create a duplicate of the annotatable, based on the MetaItem fn expand_duplicate(cx: &mut ExtCtxt, - sp: Span, + _sp: Span, mi: &MetaItem, it: &Annotatable, - push: &mut FnMut(Annotatable)) -{ + push: &mut FnMut(Annotatable)) { let copy_name = match mi.node { ast::MetaItemKind::List(_, ref xs) => { - if let ast::MetaItemKind::Word(ref w) = xs[0].node { - token::str_to_ident(&w) + if let Some(word) = xs[0].word() { + token::str_to_ident(&word.name()) } else { cx.span_err(mi.span, "Expected word"); return; @@ -142,4 +146,69 @@ fn expand_duplicate(cx: &mut ExtCtxt, } } +pub fn token_separate(ecx: &ExtCtxt, things: &[T], + token: token::Token) -> Vec { + let mut output: Vec = vec![]; + for (i, thing) in things.iter().enumerate() { + output.extend(thing.to_tokens(ecx)); + if i < things.len() - 1 { + output.push(TokenTree::Token(DUMMY_SP, token.clone())); + } + } + + output +} + +fn expand_caller(cx: &mut ExtCtxt, + sp: Span, + mi: &MetaItem, + it: &Annotatable, + push: &mut FnMut(Annotatable)) { + let (orig_fn_name, ret_type) = match *it { + Annotatable::Item(ref item) => match item.node { + ItemKind::Fn(ref decl, _, _, _, _, _) => { + (item.ident, &decl.output) + } + _ => cx.span_fatal(item.span, "Only functions with return types can be annotated.") + }, + _ => cx.span_fatal(sp, "Only functions can be annotated.") + }; + + let (caller_name, arguments) = if let Some(list) = mi.meta_item_list() { + if list.len() < 2 { + cx.span_fatal(mi.span(), "Need a function name and at least one parameter."); + } + + let fn_name = match list[0].name() { + Some(name) => token::str_to_ident(&name), + None => cx.span_fatal(list[0].span(), "First parameter must be an ident.") + }; + + (fn_name, &list[1..]) + } else { + cx.span_fatal(mi.span, "Expected list."); + }; + + let literals: Vec = arguments.iter().map(|arg| { + if let Some(lit) = arg.literal() { + lit.clone() + } else { + cx.span_fatal(arg.span(), "Expected literal."); + } + }).collect(); + + let arguments = token_separate(cx, literals.as_slice(), token::Comma); + if let ast::FunctionRetTy::Ty(ref rt) = *ret_type { + push(Annotatable::Item(quote_item!(cx, + fn $caller_name() -> $rt { + $orig_fn_name($arguments) + }).unwrap())) + } else { + push(Annotatable::Item(quote_item!(cx, + fn $caller_name() { + $orig_fn_name($arguments) + }).unwrap())) + } +} + pub fn foo() {} diff --git a/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs b/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs index f0edc0f2b120f..f21c914a76c9c 100644 --- a/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs +++ b/src/test/run-pass-fulldeps/auxiliary/plugin_args.rs @@ -30,7 +30,7 @@ use syntax::tokenstream; use rustc_plugin::Registry; struct Expander { - args: Vec>, + args: Vec, } impl TTMacroExpander for Expander { @@ -38,7 +38,7 @@ impl TTMacroExpander for Expander { ecx: &'cx mut ExtCtxt, sp: Span, _: &[tokenstream::TokenTree]) -> Box { - let args = self.args.iter().map(|i| pprust::meta_item_to_string(&*i)) + let args = self.args.iter().map(|i| pprust::meta_list_item_to_string(i)) .collect::>().join(", "); let interned = token::intern_and_get_ident(&args[..]); MacEager::expr(ecx.expr_str(sp, interned)) diff --git a/src/test/run-pass-fulldeps/macro-crate-multi-decorator-literals.rs b/src/test/run-pass-fulldeps/macro-crate-multi-decorator-literals.rs new file mode 100644 index 0000000000000..6dc651bb653a3 --- /dev/null +++ b/src/test/run-pass-fulldeps/macro-crate-multi-decorator-literals.rs @@ -0,0 +1,58 @@ +// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:macro_crate_test.rs +// ignore-stage1 + +#![feature(plugin, custom_attribute, attr_literals)] +#![plugin(macro_crate_test)] + +#[macro_use] +#[no_link] +extern crate macro_crate_test; + +// The `caller(name, args...)` attribute emits a new nullary function named +// `name` that calls the annotated function with `args`. As an example, consider +// the following: +// +// #[caller(simple, 1, "hello", 3.14)] +// fn f(num: isize, string: &'static str, float: f32) -> (isize, &'static str, float) { +// (num, string, float) +// } +// +// This results in a function named `simple` that calls `f(1, "hello", 3.14)`. +// As a result, the expression `simple()` evaluates to `(1, "helllo", 3.14)`. + +#[caller(simple, 1, "hello", 3.14)] +#[caller(simple1, 2, "bye", 6.28)] +#[caller(simple2, 3, "hi", 1.01)] +fn f(num: isize, string: &'static str, float: f32) -> (isize, &'static str, f32) { + (num, string, float) +} + +#[caller(complex, true, 10)] +#[caller(complex1, false, 15)] +#[caller(complex2, true, 20)] +fn g(emit: bool, num: i32) -> Option { + match emit { + true => Some(num), + false => None + } +} + +fn main() { + assert_eq!(simple(), (1, "hello", 3.14)); + assert_eq!(simple1(), (2, "bye", 6.28)); + assert_eq!(simple2(), (3, "hi", 1.01)); + + assert_eq!(complex(), Some(10)); + assert_eq!(complex1(), None); + assert_eq!(complex2(), Some(20)); +} From 4eb08bb2ab43f0ad80071469771381a4dd03603d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 23 Aug 2016 03:21:17 +0000 Subject: [PATCH 08/18] Refactor away `AttrNestedMetaItemMethods`. --- src/librustc/hir/check_attr.rs | 2 +- src/librustc/lint/context.rs | 2 +- src/librustc_borrowck/borrowck/mir/mod.rs | 2 +- src/librustc_incremental/assert_dep_graph.rs | 2 +- .../persist/dirty_clean.rs | 2 +- src/librustc_lint/builtin.rs | 2 +- src/librustc_metadata/creader.rs | 2 +- src/librustc_metadata/macro_import.rs | 2 +- src/librustc_plugin/load.rs | 2 +- src/librustc_trans/assert_module_sources.rs | 2 +- src/librustdoc/clean/mod.rs | 4 +- src/librustdoc/test.rs | 1 - src/librustdoc/visit_ast.rs | 2 +- src/libsyntax/attr.rs | 74 +++++++++---------- src/libsyntax/config.rs | 2 +- src/libsyntax/feature_gate.rs | 2 +- src/libsyntax/test.rs | 2 +- src/libsyntax_ext/deriving/mod.rs | 2 +- 18 files changed, 50 insertions(+), 59 deletions(-) diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 350b9fd88f6e7..42f293577b3be 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -11,7 +11,7 @@ use session::Session; use syntax::ast; -use syntax::attr::{AttrNestedMetaItemMethods, AttrMetaMethods}; +use syntax::attr::AttrMetaMethods; use syntax::visit; use syntax::visit::Visitor; diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index bccd217352b70..ed812471594ed 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -38,7 +38,7 @@ use util::nodemap::FnvHashMap; use std::cmp; use std::default::Default as StdDefault; use std::mem; -use syntax::attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods}; +use syntax::attr::{self, AttrMetaMethods}; use syntax::parse::token::InternedString; use syntax::ast; use syntax_pos::Span; diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 55c6a4de9df50..3285cecb79c4d 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -11,7 +11,7 @@ use borrowck::BorrowckCtxt; use syntax::ast::{self, MetaItem}; -use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; +use syntax::attr::AttrMetaMethods; use syntax::ptr::P; use syntax_pos::{Span, DUMMY_SP}; diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 482b351481c4e..7ab61d494b5cf 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -56,7 +56,7 @@ use std::env; use std::fs::File; use std::io::Write; use syntax::ast; -use syntax::attr::{AttrNestedMetaItemMethods, AttrMetaMethods}; +use syntax::attr::AttrMetaMethods; use syntax::parse::token::InternedString; use syntax_pos::Span; diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index f0092ce04d1f6..0a87c0833188b 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -32,7 +32,7 @@ use rustc::hir::def_id::DefId; use rustc::hir::intravisit::Visitor; use rustc_data_structures::fnv::FnvHashSet; use syntax::ast::{self, Attribute, NestedMetaItem}; -use syntax::attr::{AttrNestedMetaItemMethods, AttrMetaMethods}; +use syntax::attr::AttrMetaMethods; use syntax::parse::token::InternedString; use rustc::ty::TyCtxt; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 9a4eec2d05b7a..57afcc47d6784 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -44,7 +44,7 @@ use lint::{LintPass, LateLintPass}; use std::collections::HashSet; use syntax::{ast}; -use syntax::attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods, AttributeMethods}; +use syntax::attr::{self, AttrMetaMethods, AttributeMethods}; use syntax_pos::{Span}; use rustc::hir::{self, PatKind}; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 4dc3d04c4a23b..91b7acff03f1f 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -35,7 +35,7 @@ use syntax::ast; use syntax::abi::Abi; use syntax::codemap; use syntax::parse; -use syntax::attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods}; +use syntax::attr::{self, AttrMetaMethods}; use syntax::parse::token::InternedString; use syntax::visit; use syntax_pos::{self, Span, mk_sp, Pos}; diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs index ec0c9f455cd0c..2482a53fe48b9 100644 --- a/src/librustc_metadata/macro_import.rs +++ b/src/librustc_metadata/macro_import.rs @@ -18,7 +18,7 @@ use rustc::session::Session; use std::collections::{HashSet, HashMap}; use syntax::parse::token; use syntax::ast; -use syntax::attr::{self, AttrNestedMetaItemMethods, AttrMetaMethods}; +use syntax::attr::{self, AttrMetaMethods}; use syntax::ext; use syntax_pos::Span; diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index 5a8d2e58c558b..895645a76cba2 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -20,7 +20,7 @@ use std::env; use std::mem; use std::path::PathBuf; use syntax::ast; -use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; +use syntax::attr::{AttrMetaMethods}; use syntax_pos::{Span, COMMAND_LINE_SP}; /// Pointer to a registrar function. diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs index e2633c829761f..e0532e7476f51 100644 --- a/src/librustc_trans/assert_module_sources.rs +++ b/src/librustc_trans/assert_module_sources.rs @@ -29,7 +29,7 @@ use rustc::ty::TyCtxt; use syntax::ast; -use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; +use syntax::attr::AttrMetaMethods; use syntax::parse::token::InternedString; use {ModuleSource, ModuleTranslation}; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 02fa073dd5523..79c0bfaaa3448 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -26,7 +26,7 @@ pub use self::Visibility::*; use syntax::abi::Abi; use syntax::ast; use syntax::attr; -use syntax::attr::{AttributeMethods, AttrMetaMethods, AttrNestedMetaItemMethods}; +use syntax::attr::{AttributeMethods, AttrMetaMethods}; use syntax::codemap::Spanned; use syntax::parse::token::{self, InternedString, keywords}; use syntax::ptr::P; @@ -542,7 +542,7 @@ impl Clean for ast::Attribute { } // This is a rough approximation that gets us what we want. -impl attr::AttrNestedMetaItemMethods for Attribute { +impl Attribute { fn check_name(&self, name: &str) -> bool { self.name().map_or(false, |mi_name| &*mi_name == name) } diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 23a047f922f9d..caf05a947d366 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -141,7 +141,6 @@ pub fn run(input: &str, // Look for #![doc(test(no_crate_inject))], used by crates in the std facade fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions { use syntax::attr::AttrMetaMethods; - use syntax::attr::AttrNestedMetaItemMethods; use syntax::print::pprust; let mut opts = TestOptions { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 4e3a81b1baeac..d3397a04b3a53 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -17,7 +17,7 @@ use std::mem; use syntax::abi; use syntax::ast; use syntax::attr; -use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; +use syntax::attr::AttrMetaMethods; use syntax_pos::Span; use rustc::hir::map as hir_map; diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 4897425f2c06c..f1a820ce1d420 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -81,32 +81,47 @@ pub fn is_used(attr: &Attribute) -> bool { }) } -pub trait AttrNestedMetaItemMethods { +impl NestedMetaItem { + /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem. + pub fn meta_item(&self) -> Option<&P> { + 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 + } + } + + /// 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`. - fn check_name(&self, name: &str) -> bool { + 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 - fn name(&self) -> Option { + pub fn name(&self) -> Option { self.meta_item().and_then(|meta_item| Some(meta_item.name())) } - /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem. - fn meta_item(&self) -> Option<&P>; - - /// Returns the Lit if self is a NestedMetaItemKind::Literal. - fn literal(&self) -> Option<&Lit>; - /// Gets the string value if self is a MetaItem and the MetaItem is a /// MetaItemKind::NameValue variant containing a string, otherwise None. - fn value_str(&self) -> Option { + pub fn value_str(&self) -> Option { self.meta_item().and_then(|meta_item| meta_item.value_str()) } /// Returns a MetaItem if self is a MetaItem with Kind Word. - fn word(&self) -> Option<&P> { + pub fn word(&self) -> Option<&P> { self.meta_item().and_then(|meta_item| if meta_item.is_word() { Some(meta_item) } else { @@ -115,57 +130,34 @@ pub trait AttrNestedMetaItemMethods { } /// Gets a list of inner meta items from a list MetaItem type. - fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { + pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { self.meta_item().and_then(|meta_item| meta_item.meta_item_list()) } /// Returns `true` if the variant is MetaItem. - fn is_meta_item(&self) -> bool { + pub fn is_meta_item(&self) -> bool { self.meta_item().is_some() } /// Returns `true` if the variant is Literal. - fn is_literal(&self) -> bool { + pub fn is_literal(&self) -> bool { self.literal().is_some() } /// Returns `true` if self is a MetaItem and the meta item is a word. - fn is_word(&self) -> bool { + pub fn is_word(&self) -> bool { self.word().is_some() } /// Returns `true` if self is a MetaItem and the meta item is a ValueString. - fn is_value_str(&self) -> bool { + pub fn is_value_str(&self) -> bool { self.value_str().is_some() } /// Returns `true` if self is a MetaItem and the meta item is a list. - fn is_meta_item_list(&self) -> bool { + pub fn is_meta_item_list(&self) -> bool { self.meta_item_list().is_some() } - - /// Returns the Span for `self`. - fn span(&self) -> Span; -} - -impl AttrNestedMetaItemMethods for NestedMetaItem { - fn meta_item(&self) -> Option<&P> { - match self.node { - NestedMetaItemKind::MetaItem(ref item) => Some(&item), - _ => None - } - } - - fn literal(&self) -> Option<&Lit> { - match self.node { - NestedMetaItemKind::Literal(ref lit) => Some(&lit), - _ => None - } - } - - fn span(&self) -> Span { - self.span - } } pub trait AttrMetaMethods { @@ -431,7 +423,7 @@ pub fn contains(haystack: &[P], needle: &MetaItem) -> bool { }) } -pub fn list_contains_name(items: &[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()); diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 4663143f4b1f8..ed05dc243b32f 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, AttrNestedMetaItemMethods, HasAttrs}; +use attr::{AttrMetaMethods, HasAttrs}; use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue}; use fold::Folder; use {fold, attr}; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index df1d5c4d9ca2f..d2aa9a4cb6bff 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -27,7 +27,7 @@ use self::AttributeGate::*; use abi::Abi; use ast::{self, NodeId, PatKind}; -use attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods}; +use attr::{self, AttrMetaMethods}; use codemap::CodeMap; use syntax_pos::Span; use errors::Handler; diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index ce917f248e1ef..0a14eae7d3532 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -19,7 +19,7 @@ use std::iter; use std::slice; use std::mem; use std::vec; -use attr::{self, AttrMetaMethods, AttrNestedMetaItemMethods}; +use attr::{self, AttrMetaMethods}; use syntax_pos::{self, DUMMY_SP, NO_EXPANSION, Span, FileMap, BytePos}; use std::rc::Rc; diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index ffc1bfd6db8cd..fae17c0465bf5 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -11,7 +11,7 @@ //! The compiler code necessary to implement the `#[derive]` extensions. use syntax::ast::{self, MetaItem}; -use syntax::attr::{AttrNestedMetaItemMethods, AttrMetaMethods}; +use syntax::attr::AttrMetaMethods; use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv}; use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier}; use syntax::ext::build::AstBuilder; From e264828b27b30980f6a9c316e17dc44e6b9be09f Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 23 Aug 2016 03:39:04 +0000 Subject: [PATCH 09/18] Refactor away `AttributeMethods`. --- src/librustc/traits/error_reporting.rs | 2 +- src/librustc_incremental/calculate_svh/mod.rs | 1 - src/librustc_lint/builtin.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- src/libsyntax/attr.rs | 13 +++---------- src/libsyntax/print/pprust.rs | 2 +- 6 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index d6f263fcebeb0..b8c5ed51eabaf 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -37,7 +37,7 @@ use util::nodemap::{FnvHashMap, FnvHashSet}; use std::cmp; use std::fmt; use syntax::ast; -use syntax::attr::{AttributeMethods, AttrMetaMethods}; +use syntax::attr::AttrMetaMethods; use syntax_pos::Span; use errors::DiagnosticBuilder; diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index 42bb1a5246738..b14c20ae8d46e 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -28,7 +28,6 @@ //! at the beginning. use syntax::ast; -use syntax::attr::AttributeMethods; use std::hash::{Hash, SipHasher, Hasher}; use rustc::dep_graph::DepNode; use rustc::hir; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 57afcc47d6784..6ab53b75f5028 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -44,7 +44,7 @@ use lint::{LintPass, LateLintPass}; use std::collections::HashSet; use syntax::{ast}; -use syntax::attr::{self, AttrMetaMethods, AttributeMethods}; +use syntax::attr::{self, AttrMetaMethods}; use syntax_pos::{Span}; use rustc::hir::{self, PatKind}; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 79c0bfaaa3448..1f1844f9b73a1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -26,7 +26,7 @@ pub use self::Visibility::*; use syntax::abi::Abi; use syntax::ast; use syntax::attr; -use syntax::attr::{AttributeMethods, AttrMetaMethods}; +use syntax::attr::AttrMetaMethods; use syntax::codemap::Spanned; use syntax::parse::token::{self, InternedString, keywords}; use syntax::ptr::P; diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index f1a820ce1d420..f8fecd5fda02f 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -267,23 +267,16 @@ impl AttrMetaMethods for P { fn span(&self) -> Span { (**self).span() } } - -pub trait AttributeMethods { - fn meta(&self) -> &MetaItem; - fn with_desugared_doc(&self, f: F) -> T where - F: FnOnce(&Attribute) -> T; -} - -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(&self, f: F) -> T where + pub fn with_desugared_doc(&self, f: F) -> T where F: FnOnce(&Attribute) -> T, { if self.node.is_sugared_doc { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 562cc896aef01..0caf9ae0d78dd 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -16,7 +16,7 @@ use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::Attribute; use util::parser::AssocOp; use attr; -use attr::{AttrMetaMethods, AttributeMethods}; +use attr::AttrMetaMethods; use codemap::{self, CodeMap}; use syntax_pos::{self, BytePos}; use errors; From bfb01bbb263923106b33fdaa140a5fa464426162 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 23 Aug 2016 03:54:53 +0000 Subject: [PATCH 10/18] Refactor away `AttrMetaMethods`. --- src/librustc/hir/check_attr.rs | 1 - src/librustc/lint/context.rs | 2 +- src/librustc/middle/lang_items.rs | 1 - src/librustc/middle/recursion_limit.rs | 1 - src/librustc/middle/stability.rs | 2 +- src/librustc/session/config.rs | 2 - src/librustc/traits/error_reporting.rs | 1 - src/librustc/ty/mod.rs | 2 +- src/librustc_borrowck/borrowck/fragments.rs | 1 - src/librustc_borrowck/borrowck/mir/mod.rs | 3 - src/librustc_borrowck/borrowck/mod.rs | 1 - src/librustc_driver/driver.rs | 2 +- src/librustc_driver/lib.rs | 1 - src/librustc_incremental/assert_dep_graph.rs | 1 - .../persist/dirty_clean.rs | 1 - src/librustc_lint/bad_style.rs | 2 +- src/librustc_lint/builtin.rs | 4 +- src/librustc_lint/unused.rs | 2 +- src/librustc_metadata/creader.rs | 2 +- src/librustc_metadata/macro_import.rs | 2 +- src/librustc_mir/hair/cx/mod.rs | 1 - src/librustc_plugin/load.rs | 1 - src/librustc_trans/assert_module_sources.rs | 1 - src/librustc_trans/back/link.rs | 1 - src/librustc_trans/base.rs | 1 - src/librustc_trans/consts.rs | 2 +- src/librustc_trans/symbol_names_test.rs | 1 - src/librustc_typeck/check/mod.rs | 1 - src/librustdoc/clean/mod.rs | 59 +----------- src/librustdoc/test.rs | 1 - src/librustdoc/visit_ast.rs | 1 - src/libsyntax/attr.rs | 92 +++++++------------ src/libsyntax/config.rs | 2 +- src/libsyntax/ext/expand.rs | 1 - src/libsyntax/feature_gate.rs | 2 +- src/libsyntax/parse/mod.rs | 2 +- src/libsyntax/print/pprust.rs | 1 - src/libsyntax/test.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 1 - src/libsyntax_ext/deriving/mod.rs | 1 - 40 files changed, 50 insertions(+), 158 deletions(-) diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 42f293577b3be..21143f93a7da8 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -11,7 +11,6 @@ use session::Session; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax::visit; use syntax::visit::Visitor; diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index ed812471594ed..c921158614327 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -38,7 +38,7 @@ use util::nodemap::FnvHashMap; use std::cmp; use std::default::Default as StdDefault; use std::mem; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax::parse::token::InternedString; use syntax::ast; use syntax_pos::Span; diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index a209b1d1abd7c..d1769d5cbc51b 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -30,7 +30,6 @@ use middle::weak_lang_items; use util::nodemap::FnvHashMap; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax::parse::token::InternedString; use hir::intravisit::Visitor; use hir; diff --git a/src/librustc/middle/recursion_limit.rs b/src/librustc/middle/recursion_limit.rs index 7dcd358165c92..0764e817f4307 100644 --- a/src/librustc/middle/recursion_limit.rs +++ b/src/librustc/middle/recursion_limit.rs @@ -17,7 +17,6 @@ use session::Session; use syntax::ast; -use syntax::attr::AttrMetaMethods; pub fn update_recursion_limit(sess: &Session, krate: &ast::Crate) { for attr in &krate.attrs { diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index cbbc2c4f98f5e..405202bc634e4 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -27,7 +27,7 @@ use syntax_pos::{Span, DUMMY_SP}; use syntax::ast; use syntax::ast::{NodeId, Attribute}; use syntax::feature_gate::{GateIssue, emit_feature_err, find_lang_feature_accepted_version}; -use syntax::attr::{self, Stability, Deprecation, AttrMetaMethods}; +use syntax::attr::{self, Stability, Deprecation}; use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap}; use hir; diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 8a32797dbd75a..7a1848f42d212 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -25,7 +25,6 @@ use middle::cstore; use syntax::ast::{self, IntTy, UintTy}; use syntax::attr; -use syntax::attr::AttrMetaMethods; use syntax::parse; use syntax::parse::token::InternedString; use syntax::feature_gate::UnstableFeatures; @@ -1774,7 +1773,6 @@ mod tests { use std::rc::Rc; use super::{OutputType, OutputTypes, Externs, PanicStrategy}; use syntax::attr; - use syntax::attr::AttrMetaMethods; fn optgroups() -> Vec { super::rustc_optgroups().into_iter() diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index b8c5ed51eabaf..a09ce38c4bb1a 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -37,7 +37,6 @@ use util::nodemap::{FnvHashMap, FnvHashSet}; use std::cmp; use std::fmt; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax_pos::Span; use errors::DiagnosticBuilder; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6c82157c8ca7c..ded9867fa6f2a 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -43,7 +43,7 @@ use std::rc::Rc; use std::slice; use std::vec::IntoIter; use syntax::ast::{self, CrateNum, Name, NodeId}; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax::parse::token::InternedString; use syntax_pos::{DUMMY_SP, Span}; diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index d3d6fa9eb52b5..a8993724e6706 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -27,7 +27,6 @@ use rustc::middle::mem_categorization as mc; use std::mem; use std::rc::Rc; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax_pos::{Span, DUMMY_SP}; #[derive(PartialEq, Eq, PartialOrd, Ord)] diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 3285cecb79c4d..2d429aaab6a08 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -11,7 +11,6 @@ use borrowck::BorrowckCtxt; use syntax::ast::{self, MetaItem}; -use syntax::attr::AttrMetaMethods; use syntax::ptr::P; use syntax_pos::{Span, DUMMY_SP}; @@ -127,8 +126,6 @@ fn do_dataflow<'a, 'tcx, BD>(tcx: TyCtxt<'a, 'tcx, 'tcx>, bd: BD) -> DataflowResults where BD: BitDenotation> + DataflowOperator { - use syntax::attr::AttrMetaMethods; - let name_found = |sess: &Session, attrs: &[ast::Attribute], name| -> Option { if let Some(item) = has_rustc_mir_with(attrs, name) { if let Some(s) = item.value_str() { diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 225895adefa4b..343e9251e1db6 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -42,7 +42,6 @@ use std::fmt; use std::mem; use std::rc::Rc; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax_pos::{MultiSpan, Span}; use errors::DiagnosticBuilder; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 3f2f6c84da190..c6ab4578f0632 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -49,7 +49,7 @@ use std::fs; use std::io::{self, Write}; use std::path::{Path, PathBuf}; use syntax::{ast, diagnostics, visit}; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax::parse::{self, PResult, token}; use syntax::util::node_count::NodeCounter; use syntax; diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 1f3f823d0b8ab..efadf1ff488df 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -95,7 +95,6 @@ use std::thread; use rustc::session::early_error; use syntax::{ast, json}; -use syntax::attr::AttrMetaMethods; use syntax::codemap::{CodeMap, FileLoader, RealFileLoader}; use syntax::feature_gate::{GatedCfg, UnstableFeatures}; use syntax::parse::{self, PResult}; diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 7ab61d494b5cf..8df8f50037118 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -56,7 +56,6 @@ use std::env; use std::fs::File; use std::io::Write; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax::parse::token::InternedString; use syntax_pos::Span; diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 0a87c0833188b..fda7ef207a344 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -32,7 +32,6 @@ use rustc::hir::def_id::DefId; use rustc::hir::intravisit::Visitor; use rustc_data_structures::fnv::FnvHashSet; use syntax::ast::{self, Attribute, NestedMetaItem}; -use syntax::attr::AttrMetaMethods; use syntax::parse::token::InternedString; use rustc::ty::TyCtxt; diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 15914838acf0d..0e130c3bb66bf 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -14,7 +14,7 @@ use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass}; use syntax::ast; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax_pos::Span; use rustc::hir::{self, PatKind}; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 6ab53b75f5028..a103386e2c980 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -44,7 +44,7 @@ use lint::{LintPass, LateLintPass}; use std::collections::HashSet; use syntax::{ast}; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax_pos::{Span}; use rustc::hir::{self, PatKind}; @@ -1145,7 +1145,7 @@ impl LintPass for UnstableFeatures { impl LateLintPass for UnstableFeatures { fn check_attribute(&mut self, ctx: &LateContext, attr: &ast::Attribute) { - if attr::contains_name(&[attr.meta().clone()], "feature") { + if attr.meta().check_name("feature") { if let Some(items) = attr.meta().meta_item_list() { for item in items { ctx.span_lint(UNSTABLE_FEATURES, item.span(), "unstable feature"); diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 44c2ffe45ccb4..411daa0c12aee 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -18,7 +18,7 @@ use lint::{LintPass, EarlyLintPass, LateLintPass}; use std::collections::hash_map::Entry::{Occupied, Vacant}; use syntax::ast; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType}; use syntax::ptr::P; use syntax_pos::Span; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 91b7acff03f1f..7e1f3ea618c97 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -35,7 +35,7 @@ use syntax::ast; use syntax::abi::Abi; use syntax::codemap; use syntax::parse; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax::parse::token::InternedString; use syntax::visit; use syntax_pos::{self, Span, mk_sp, Pos}; diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs index 2482a53fe48b9..25fedb10201a9 100644 --- a/src/librustc_metadata/macro_import.rs +++ b/src/librustc_metadata/macro_import.rs @@ -18,7 +18,7 @@ use rustc::session::Session; use std::collections::{HashSet, HashMap}; use syntax::parse::token; use syntax::ast; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax::ext; use syntax_pos::Span; diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 972e7f5be7075..f65680b567c74 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -32,7 +32,6 @@ use rustc::ty::{self, Ty, TyCtxt}; use syntax::parse::token; use rustc::hir; use rustc_const_math::{ConstInt, ConstUsize}; -use syntax::attr::AttrMetaMethods; #[derive(Copy, Clone)] pub struct Cx<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index 895645a76cba2..9e56397bc99e9 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -20,7 +20,6 @@ use std::env; use std::mem; use std::path::PathBuf; use syntax::ast; -use syntax::attr::{AttrMetaMethods}; use syntax_pos::{Span, COMMAND_LINE_SP}; /// Pointer to a registrar function. diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs index e0532e7476f51..7fe6d2bbfe24e 100644 --- a/src/librustc_trans/assert_module_sources.rs +++ b/src/librustc_trans/assert_module_sources.rs @@ -29,7 +29,6 @@ use rustc::ty::TyCtxt; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax::parse::token::InternedString; use {ModuleSource, ModuleTranslation}; diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 9f401b13d6f97..b21785c27dae5 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -42,7 +42,6 @@ use std::process::Command; use std::str; use flate; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax_pos::Span; // RLIB LLVM-BYTECODE OBJECT LAYOUT diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 165884c8f55a2..f231344f22f45 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -93,7 +93,6 @@ use std::rc::Rc; use std::str; use std::i32; use syntax_pos::{Span, DUMMY_SP}; -use syntax::attr::AttrMetaMethods; use syntax::attr; use rustc::hir; use syntax::ast; diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index fa1e008d496e4..2b6e2a23261bd 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -29,7 +29,7 @@ use rustc::hir; use std::ffi::{CStr, CString}; use syntax::ast; -use syntax::attr::{self, AttrMetaMethods}; +use syntax::attr; use syntax::parse::token; pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef { diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs index 9a7fe54e0d9f5..25c30151ad45d 100644 --- a/src/librustc_trans/symbol_names_test.rs +++ b/src/librustc_trans/symbol_names_test.rs @@ -17,7 +17,6 @@ use rustc::hir; use rustc::hir::intravisit::{self, Visitor}; use syntax::ast; -use syntax::attr::AttrMetaMethods; use common::SharedCrateContext; use monomorphize::Instance; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 16300d869abf5..619aafa799f3e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -113,7 +113,6 @@ use std::ops::Deref; use syntax::abi::Abi; use syntax::ast; use syntax::attr; -use syntax::attr::AttrMetaMethods; use syntax::codemap::{self, Spanned}; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::parse::token::{self, InternedString, keywords}; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1f1844f9b73a1..3a1e22f81b5c9 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -26,9 +26,8 @@ pub use self::Visibility::*; use syntax::abi::Abi; use syntax::ast; use syntax::attr; -use syntax::attr::AttrMetaMethods; use syntax::codemap::Spanned; -use syntax::parse::token::{self, InternedString, keywords}; +use syntax::parse::token::keywords; use syntax::ptr::P; use syntax::print::pprust as syntax_pprust; use syntax_pos::{self, DUMMY_SP, Pos}; @@ -541,62 +540,6 @@ impl Clean for ast::Attribute { } } -// This is a rough approximation that gets us what we want. -impl Attribute { - fn check_name(&self, name: &str) -> bool { - self.name().map_or(false, |mi_name| &*mi_name == name) - } - - fn literal(&self) -> Option<&ast::Lit> { None } - - fn is_literal(&self) -> bool { - match *self { - Literal(..) => true, - _ => false, - } - } - - fn meta_item(&self) -> Option<&P> { None } - - fn name(&self) -> Option { - match *self { - Word(ref n) | List(ref n, _) | NameValue(ref n, _) => { - Some(token::intern_and_get_ident(n)) - }, - _ => None - } - } - - fn value_str(&self) -> Option { - match *self { - NameValue(_, ref v) => { - Some(token::intern_and_get_ident(v)) - } - _ => None, - } - } - - fn word(&self) -> Option<&P> { None } - - fn is_word(&self) -> bool { - match *self { - Word(_) => true, - _ => false, - } - } - - fn meta_item_list<'a>(&'a self) -> Option<&'a [ast::NestedMetaItem]> { None } - - fn is_meta_item_list(&self) -> bool { - match *self { - List(..) => true, - _ => false, - } - } - - fn span(&self) -> syntax_pos::Span { unimplemented!() } -} - #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] pub struct TyParam { pub name: String, diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index caf05a947d366..1805da2385b67 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -140,7 +140,6 @@ pub fn run(input: &str, // Look for #![doc(test(no_crate_inject))], used by crates in the std facade fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions { - use syntax::attr::AttrMetaMethods; use syntax::print::pprust; let mut opts = TestOptions { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index d3397a04b3a53..e66d01e5c2db1 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -17,7 +17,6 @@ use std::mem; use syntax::abi; use syntax::ast; use syntax::attr; -use syntax::attr::AttrMetaMethods; use syntax_pos::Span; use rustc::hir::map as hir_map; diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index f8fecd5fda02f..6060ff529f215 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -160,40 +160,8 @@ impl NestedMetaItem { } } -pub trait AttrMetaMethods { - fn check_name(&self, name: &str) -> bool { - name == &self.name()[..] - } - - /// Retrieve the name of the meta item, e.g. `foo` in `#[foo]`, - /// `#[foo="bar"]` and `#[foo(bar)]` - fn name(&self) -> InternedString; - - /// Gets the string value if self is a MetaItemKind::NameValue variant - /// containing a string, otherwise None. - fn value_str(&self) -> Option; - - /// Gets a list of inner meta items from a list MetaItem type. - fn meta_item_list(&self) -> Option<&[NestedMetaItem]>; - - /// Indicates if the attribute is a Word. - fn is_word(&self) -> bool; - - /// Indicates if the attribute is a Value String. - 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 { - 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); @@ -201,23 +169,32 @@ impl AttrMetaMethods for Attribute { matches } - fn name(&self) -> InternedString { self.meta().name() } + pub fn name(&self) -> InternedString { self.meta().name() } - fn value_str(&self) -> Option { + pub fn value_str(&self) -> Option { self.meta().value_str() } - fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { + 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 } - fn span(&self) -> Span { self.meta().span } + pub fn is_meta_item_list(&self) -> bool { + self.meta_item_list().is_some() + } + + /// 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(), @@ -225,7 +202,7 @@ impl AttrMetaMethods for MetaItem { } } - fn value_str(&self) -> Option { + pub fn value_str(&self) -> Option { match self.node { MetaItemKind::NameValue(_, ref v) => { match v.node { @@ -237,34 +214,33 @@ impl AttrMetaMethods for MetaItem { } } - fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { + 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 } + + pub fn check_name(&self, name: &str) -> bool { + name == &self.name()[..] + } -// Annoying, but required to get test_cfg to work -impl AttrMetaMethods for P { - fn name(&self) -> InternedString { (**self).name() } - fn value_str(&self) -> Option { (**self).value_str() } - fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { - (**self).meta_item_list() + pub fn is_value_str(&self) -> bool { + self.value_str().is_some() + } + + pub fn is_meta_item_list(&self) -> bool { + self.meta_item_list().is_some() } - 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() } } impl Attribute { @@ -424,9 +400,9 @@ pub fn list_contains_name(items: &[NestedMetaItem], name: &str) -> bool { }) } -pub fn contains_name(metas: &[AM], name: &str) -> bool { +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) }) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index ed05dc243b32f..ff1ecd443717e 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}; diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 031d9a2d3f46e..bc0f4de4471fb 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 d2aa9a4cb6bff..cd2705fb7d8e8 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -27,7 +27,7 @@ use self::AttributeGate::*; use abi::Abi; use ast::{self, NodeId, PatKind}; -use attr::{self, AttrMetaMethods}; +use attr; use codemap::CodeMap; use syntax_pos::Span; use errors::Handler; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index cd1fdcfe9d130..6f06dd14d8fc7 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -678,7 +678,7 @@ mod tests { 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}; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 0caf9ae0d78dd..28f1016c51f36 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; use codemap::{self, CodeMap}; use syntax_pos::{self, BytePos}; use errors; diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 0a14eae7d3532..e3e2457c471c0 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -19,7 +19,7 @@ use std::iter; use std::slice; use std::mem; use std::vec; -use attr::{self, AttrMetaMethods}; +use attr; use syntax_pos::{self, DUMMY_SP, NO_EXPANSION, Span, FileMap, BytePos}; use std::rc::Rc; diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index bae40ddf45c9f..0d69fc007997f 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -194,7 +194,6 @@ use std::vec; use syntax::abi::Abi; use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind, VariantData}; use syntax::attr; -use syntax::attr::AttrMetaMethods; use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::codemap::{self, respan}; diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index fae17c0465bf5..81085122e875b 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -11,7 +11,6 @@ //! The compiler code necessary to implement the `#[derive]` extensions. use syntax::ast::{self, MetaItem}; -use syntax::attr::AttrMetaMethods; use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv}; use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier}; use syntax::ext::build::AstBuilder; From 469753f0abc4b9eac811d8b2955d478825f9c3e1 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 24 Aug 2016 23:59:18 +0000 Subject: [PATCH 11/18] Fix fallout in tests. --- src/librustc/session/config.rs | 8 ++++++-- .../compile-fail-fulldeps/auxiliary/macro_crate_test.rs | 1 - .../auxiliary/custom_derive_plugin_attr.rs | 1 - src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs | 1 - 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 7a1848f42d212..562dce6a1b129 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1772,7 +1772,9 @@ mod tests { use std::path::PathBuf; use std::rc::Rc; use super::{OutputType, OutputTypes, Externs, PanicStrategy}; - use syntax::attr; + use syntax::{ast, attr}; + use syntax::parse::token::InternedString; + use syntax::codemap::dummy_spanned; fn optgroups() -> Vec { super::rustc_optgroups().into_iter() @@ -1801,7 +1803,9 @@ mod tests { let (sessopts, cfg) = build_session_options_and_crate_config(matches); let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore)); let cfg = build_configuration(&sess, cfg); - assert!((attr::contains_name(&cfg[..], "test"))); + assert!(attr::contains(&cfg, &dummy_spanned(ast::MetaItemKind::Word({ + InternedString::new("test") + })))); } // When the user supplies --test and --cfg test, don't implicitly add diff --git a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs index 6db10eeae769b..5a3412b7ed9f9 100644 --- a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs @@ -18,7 +18,6 @@ extern crate rustc; extern crate rustc_plugin; use syntax::ast::{self, Item, MetaItem, ItemKind}; -use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax::ext::base::*; use syntax::parse::{self, token}; use syntax::ptr::P; diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs index 882e90b2d6c15..91b4b74797a83 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs @@ -21,7 +21,6 @@ extern crate rustc; extern crate rustc_plugin; use syntax::ast; -use syntax::attr::AttrMetaMethods; use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable}; use syntax::ext::build::AstBuilder; use syntax::parse::token; diff --git a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs index e37cd89f29991..46fdf91125845 100644 --- a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs +++ b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs @@ -19,7 +19,6 @@ extern crate syntax_pos; use syntax::ast::{self, Item, MetaItem, ItemKind}; use syntax::codemap::DUMMY_SP; -use syntax::attr::{AttrMetaMethods, AttrNestedMetaItemMethods}; use syntax::ext::base::*; use syntax::ext::quote::rt::ToTokens; use syntax::parse::{self, token}; From 1e9e798ccea7f70480c3bcc86e271ca2191b8675 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Sun, 7 Aug 2016 14:33:35 -0700 Subject: [PATCH 12/18] Move E0379 check from typeck to ast validation --- src/librustc_passes/ast_validation.rs | 21 +++++++++++++++ src/librustc_passes/diagnostics.rs | 7 +++++ src/librustc_typeck/check/mod.rs | 26 ++----------------- src/librustc_typeck/diagnostics.rs | 7 ----- src/test/compile-fail/const-fn-mismatch.rs | 2 +- .../compile-fail/const-fn-not-in-trait.rs | 8 ++++-- 6 files changed, 37 insertions(+), 34 deletions(-) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 46124d0f97359..f10f1fba4c25e 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -69,6 +69,17 @@ impl<'a> AstValidator<'a> { } } } + + fn check_trait_fn_not_const(&self, span: Span, constness: Constness) { + match constness { + Constness::Const => { + struct_span_err!(self.session, span, E0379, "trait fns cannot be declared const") + .span_label(span, &format!("trait fns cannot be const")) + .emit(); + } + _ => {} + } + } } impl<'a> Visitor for AstValidator<'a> { @@ -146,6 +157,9 @@ impl<'a> Visitor for AstValidator<'a> { self.invalid_visibility(&item.vis, item.span, None); for impl_item in impl_items { self.invalid_visibility(&impl_item.vis, impl_item.span, None); + if let ImplItemKind::Method(ref sig, _) = impl_item.node { + self.check_trait_fn_not_const(impl_item.span, sig.constness); + } } } ItemKind::Impl(_, _, _, None, _, _) => { @@ -169,6 +183,13 @@ impl<'a> Visitor for AstValidator<'a> { } } } + ItemKind::Trait(_, _, _, ref trait_items) => { + for trait_item in trait_items { + if let TraitItemKind::Method(ref sig, _) = trait_item.node { + self.check_trait_fn_not_const(trait_item.span, sig.constness); + } + } + } ItemKind::Mod(_) => { // Ensure that `path` attributes on modules are recorded as used (c.f. #35584). attr::first_attr_value_str_by_name(&item.attrs, "path"); diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs index 7049040678e39..89b8aa81411b3 100644 --- a/src/librustc_passes/diagnostics.rs +++ b/src/librustc_passes/diagnostics.rs @@ -176,6 +176,13 @@ fn some_func() { ``` "##, +E0379: r##" +Trait methods cannot be declared `const` by design. For more information, see +[RFC 911]. + +[RFC 911]: https://github.com/rust-lang/rfcs/pull/911 +"##, + E0449: r##" A visibility qualifier was used when it was unnecessary. Erroneous code examples: diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e972a5ca7fb38..c8d2f9144dcc6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -836,13 +836,9 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { check_const(ccx, &expr, trait_item.id) } hir::MethodTraitItem(ref sig, Some(ref body)) => { - check_trait_fn_not_const(ccx, trait_item.span, sig.constness); - check_bare_fn(ccx, &sig.decl, body, trait_item.id); } - hir::MethodTraitItem(ref sig, None) => { - check_trait_fn_not_const(ccx, trait_item.span, sig.constness); - } + hir::MethodTraitItem(_, None) | hir::ConstTraitItem(_, None) | hir::TypeTraitItem(..) => { // Nothing to do. @@ -854,22 +850,6 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { } } -fn check_trait_fn_not_const<'a,'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - span: Span, - constness: hir::Constness) -{ - match constness { - hir::Constness::NotConst => { - // good - } - hir::Constness::Const => { - struct_span_err!(ccx.tcx.sess, span, E0379, "trait fns cannot be declared const") - .span_label(span, &format!("trait fns cannot be const")) - .emit() - } - } -} - fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, def_id: DefId, item: &hir::Item) { @@ -1027,9 +1007,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, err.emit() } } - hir::ImplItemKind::Method(ref sig, ref body) => { - check_trait_fn_not_const(ccx, impl_item.span, sig.constness); - + hir::ImplItemKind::Method(_, ref body) => { let impl_method = match ty_impl_item { ty::MethodTraitItem(ref mti) => mti, _ => span_bug!(impl_item.span, "non-method impl-item for method") diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 8bb5efdcad2c3..3f1374db36936 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3422,13 +3422,6 @@ containing the unsized type is the last and only unsized type field in the struct. "##, -E0379: r##" -Trait methods cannot be declared `const` by design. For more information, see -[RFC 911]. - -[RFC 911]: https://github.com/rust-lang/rfcs/pull/911 -"##, - E0380: r##" Default impls are only allowed for traits with no methods or associated items. For more information see the [opt-in builtin traits RFC](https://github.com/rust diff --git a/src/test/compile-fail/const-fn-mismatch.rs b/src/test/compile-fail/const-fn-mismatch.rs index 92568b27f7c1d..7ea72e23779ec 100644 --- a/src/test/compile-fail/const-fn-mismatch.rs +++ b/src/test/compile-fail/const-fn-mismatch.rs @@ -21,7 +21,7 @@ trait Foo { impl Foo for u32 { const fn f() -> u32 { 22 } - //~^ ERROR E0379 + //~^ ERROR trait fns cannot be declared const //~| NOTE trait fns cannot be const } diff --git a/src/test/compile-fail/const-fn-not-in-trait.rs b/src/test/compile-fail/const-fn-not-in-trait.rs index 191f3e025270f..257d4d5ee9921 100644 --- a/src/test/compile-fail/const-fn-not-in-trait.rs +++ b/src/test/compile-fail/const-fn-not-in-trait.rs @@ -14,8 +14,12 @@ #![feature(const_fn)] trait Foo { - const fn f() -> u32; //~ ERROR trait fns cannot be declared const - const fn g() -> u32 { 0 } //~ ERROR trait fns cannot be declared const + const fn f() -> u32; + //~^ ERROR trait fns cannot be declared const + //~| NOTE trait fns cannot be const + const fn g() -> u32 { 0 } + //~^ ERROR trait fns cannot be declared const + //~| NOTE trait fns cannot be const } fn main() { } From aa5c4bb05d1d5d10a2fdbb80f098ba06e73214b9 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Wed, 10 Aug 2016 16:20:12 -0700 Subject: [PATCH 13/18] Change Constness to Spanned --- src/librustc/hir/lowering.rs | 4 +-- src/librustc/hir/map/blocks.rs | 6 ++--- src/librustc/infer/error_reporting.rs | 3 ++- src/librustc_passes/ast_validation.rs | 14 +++++----- src/librustc_passes/consts.rs | 3 ++- src/libsyntax/ast.rs | 4 +-- src/libsyntax/ext/build.rs | 4 +-- src/libsyntax/feature_gate.rs | 8 +++--- src/libsyntax/parse/mod.rs | 5 +++- src/libsyntax/parse/parser.rs | 33 ++++++++++++++++------- src/libsyntax/print/pprust.rs | 4 +-- src/libsyntax/test.rs | 4 +-- src/libsyntax/visit.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 5 ++-- 14 files changed, 61 insertions(+), 38 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index b45610c3fe820..be5eb7f83769e 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -809,8 +809,8 @@ impl<'a> LoweringContext<'a> { } } - fn lower_constness(&mut self, c: Constness) -> hir::Constness { - match c { + fn lower_constness(&mut self, c: Spanned) -> hir::Constness { + match c.node { Constness::Const => hir::Constness::Const, Constness::NotConst => hir::Constness::NotConst, } diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs index 50e8c6e7ab842..4487234885692 100644 --- a/src/librustc/hir/map/blocks.rs +++ b/src/librustc/hir/map/blocks.rs @@ -23,13 +23,13 @@ pub use self::Code::*; +use hir as ast; use hir::map::{self, Node}; -use syntax::abi; use hir::{Block, FnDecl}; +use hir::intravisit::FnKind; +use syntax::abi; use syntax::ast::{Attribute, Name, NodeId}; -use hir as ast; use syntax_pos::Span; -use hir::intravisit::FnKind; /// An FnLikeNode is a Node that is like a fn, in that it has a decl /// and a body (as well as a NodeId, a span, etc). diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 9169d299e040b..eab7f37382e67 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -1030,7 +1030,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { = node_inner.expect("expect item fn"); let rebuilder = Rebuilder::new(self.tcx, fn_decl, generics, same_regions, &life_giver); let (fn_decl, generics) = rebuilder.rebuild(); - self.give_expl_lifetime_param(err, &fn_decl, unsafety, constness, name, &generics, span); + self.give_expl_lifetime_param( + err, &fn_decl, unsafety, constness, name, &generics, span); } pub fn issue_32330_warnings(&self, span: Span, issue32330s: &[ty::Issue32330]) { diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index f10f1fba4c25e..dde1a4a759563 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -20,6 +20,7 @@ use rustc::lint; use rustc::session::Session; use syntax::ast::*; use syntax::attr; +use syntax::codemap::Spanned; use syntax::parse::token::{self, keywords}; use syntax::visit::{self, Visitor}; use syntax_pos::Span; @@ -70,11 +71,12 @@ impl<'a> AstValidator<'a> { } } - fn check_trait_fn_not_const(&self, span: Span, constness: Constness) { - match constness { + fn check_trait_fn_not_const(&self, constness: Spanned) { + match constness.node { Constness::Const => { - struct_span_err!(self.session, span, E0379, "trait fns cannot be declared const") - .span_label(span, &format!("trait fns cannot be const")) + struct_span_err!(self.session, constness.span, E0379, + "trait fns cannot be declared const") + .span_label(constness.span, &format!("trait fns cannot be const")) .emit(); } _ => {} @@ -158,7 +160,7 @@ impl<'a> Visitor for AstValidator<'a> { for impl_item in impl_items { self.invalid_visibility(&impl_item.vis, impl_item.span, None); if let ImplItemKind::Method(ref sig, _) = impl_item.node { - self.check_trait_fn_not_const(impl_item.span, sig.constness); + self.check_trait_fn_not_const(sig.constness); } } } @@ -186,7 +188,7 @@ impl<'a> Visitor for AstValidator<'a> { ItemKind::Trait(_, _, _, ref trait_items) => { for trait_item in trait_items { if let TraitItemKind::Method(ref sig, _) = trait_item.node { - self.check_trait_fn_not_const(trait_item.span, sig.constness); + self.check_trait_fn_not_const(sig.constness); } } } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 4aae6d690c4df..2d1b6e1315f8b 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -147,7 +147,8 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { } let mode = match fk { - FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _, _) => Mode::ConstFn, + FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _, _) + => Mode::ConstFn, FnKind::Method(_, m, _, _) => { if m.constness == hir::Constness::Const { Mode::ConstFn diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f8a5cb0b04a8e..427a44d2e740c 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1120,7 +1120,7 @@ pub struct MutTy { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct MethodSig { pub unsafety: Unsafety, - pub constness: Constness, + pub constness: Spanned, pub abi: Abi, pub decl: P, pub generics: Generics, @@ -1846,7 +1846,7 @@ pub enum ItemKind { /// A function declaration (`fn` or `pub fn`). /// /// E.g. `fn foo(bar: usize) -> usize { .. }` - Fn(P, Unsafety, Constness, Abi, Generics, P), + Fn(P, Unsafety, Spanned, Abi, Generics, P), /// A module declaration (`mod` or `pub mod`). /// /// E.g. `mod foo;` or `mod foo { .. }` diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 5d6429f7bdfff..14c7e46246d0d 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; @@ -1016,7 +1016,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)) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index dc68e06463464..9114c31d29816 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -30,7 +30,7 @@ use ast::{NodeId, PatKind}; use ast; use attr; use attr::AttrMetaMethods; -use codemap::CodeMap; +use codemap::{CodeMap, Spanned}; use syntax_pos::Span; use errors::Handler; use visit::{self, FnKind, Visitor}; @@ -1046,7 +1046,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 +1078,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 +1105,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"); } } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index cd1fdcfe9d130..a89dc80df4b08 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -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(), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 1646246069ead..757c0779e352a 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; @@ -4768,7 +4768,7 @@ impl<'a> Parser<'a> { /// Parse an item-position function declaration. fn parse_item_fn(&mut self, unsafety: Unsafety, - constness: Constness, + constness: Spanned, abi: abi::Abi) -> PResult<'a, ItemInfo> { let (ident, mut generics) = self.parse_fn_header()?; @@ -4794,18 +4794,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::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 +5707,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 +5746,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 +5758,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 +5824,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 +5848,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, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index a77c678248b56..4c83440306306 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1184,7 +1184,7 @@ impl<'a> State<'a> { try!(self.print_fn( decl, unsafety, - constness, + constness.node, abi, Some(item.ident), typarams, @@ -1518,7 +1518,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, diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index faf6a17a15045..cbf9aa8c6c17f 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -24,7 +24,7 @@ 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; @@ -485,7 +485,7 @@ fn mk_main(cx: &mut TestCtxt) -> P { 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 582412119caa8..d75110b2654ce 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, Abi, &'a Visibility), /// fn foo(&self) Method(Ident, &'a MethodSig, Option<&'a Visibility>), diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index cd49e7ec9d2c6..809f444b9936e 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -197,7 +197,7 @@ use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; -use syntax::codemap::{self, respan}; +use syntax::codemap::{self, dummy_spanned, respan}; use syntax::util::move_map::MoveMap; use syntax::parse::token::{InternedString, keywords}; use syntax::ptr::P; @@ -901,7 +901,8 @@ impl<'a> MethodDef<'a> { generics: fn_generics, abi: abi, unsafety: unsafety, - constness: ast::Constness::NotConst, + constness: + dummy_spanned(ast::Constness::NotConst), decl: fn_decl, }, body_block), From e46b09a1f9051a65544dee08f4d8d749d474d586 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Fri, 12 Aug 2016 15:47:42 -0700 Subject: [PATCH 14/18] Add UI test for E0379 --- .../ui/mismatched_types/const-fn-in-trait.rs | 25 +++++++++++++++++++ .../mismatched_types/const-fn-in-trait.stderr | 14 +++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/test/ui/mismatched_types/const-fn-in-trait.rs create mode 100644 src/test/ui/mismatched_types/const-fn-in-trait.stderr diff --git a/src/test/ui/mismatched_types/const-fn-in-trait.rs b/src/test/ui/mismatched_types/const-fn-in-trait.rs new file mode 100644 index 0000000000000..5e44030eab71a --- /dev/null +++ b/src/test/ui/mismatched_types/const-fn-in-trait.rs @@ -0,0 +1,25 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// rustc-env:RUST_NEW_ERROR_FORMAT + +#![feature(const_fn)] + +trait Foo { + fn f() -> u32; + const fn g(); +} + +impl Foo for u32 { + const fn f() -> u32 { 22 } + fn g() {} +} + +fn main() { } diff --git a/src/test/ui/mismatched_types/const-fn-in-trait.stderr b/src/test/ui/mismatched_types/const-fn-in-trait.stderr new file mode 100644 index 0000000000000..f7b7635e41aec --- /dev/null +++ b/src/test/ui/mismatched_types/const-fn-in-trait.stderr @@ -0,0 +1,14 @@ +error[E0379]: trait fns cannot be declared const + --> $DIR/const-fn-in-trait.rs:17:5 + | +17 | const fn g(); + | ^^^^^ trait fns cannot be const + +error[E0379]: trait fns cannot be declared const + --> $DIR/const-fn-in-trait.rs:21:5 + | +21 | const fn f() -> u32 { 22 } + | ^^^^^ trait fns cannot be const + +error: aborting due to 2 previous errors + From 4fe94e0be65865bef1d0283873158baa523afddc Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 29 Aug 2016 05:04:31 +0000 Subject: [PATCH 15/18] Future proof the AST for `union`. --- src/librustc/hir/lowering.rs | 1 + src/librustc/hir/map/def_collector.rs | 4 ++-- src/librustc_resolve/build_reduced_graph.rs | 2 ++ src/librustc_resolve/lib.rs | 1 + src/libsyntax/ast.rs | 5 +++++ src/libsyntax/config.rs | 3 +++ src/libsyntax/fold.rs | 4 ++++ src/libsyntax/print/pprust.rs | 5 ++++- src/libsyntax/visit.rs | 3 ++- 9 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 24792e634a5d2..6739d3f662ac6 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -638,6 +638,7 @@ impl<'a> LoweringContext<'a> { let struct_def = self.lower_variant_data(struct_def); hir::ItemStruct(struct_def, self.lower_generics(generics)) } + ItemKind::Union(..) => panic!("`union` is not yet implemented"), ItemKind::DefaultImpl(unsafety, ref trait_ref) => { hir::ItemDefaultImpl(self.lower_unsafety(unsafety), self.lower_trait_ref(trait_ref)) diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 752b0e9a253dd..77567fc7a4603 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -133,7 +133,7 @@ impl<'ast> visit::Visitor for DefCollector<'ast> { let def_data = match i.node { ItemKind::DefaultImpl(..) | ItemKind::Impl(..) => DefPathData::Impl, - ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Trait(..) | + ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | ItemKind::Trait(..) | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) => DefPathData::TypeNs(i.ident.name.as_str()), ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()), @@ -164,7 +164,7 @@ impl<'ast> visit::Visitor for DefCollector<'ast> { }); } } - ItemKind::Struct(ref struct_def, _) => { + ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => { // If this is a tuple-like struct, register the constructor. if !struct_def.is_struct() { this.create_def(struct_def.id(), diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 12c55b3ac172c..71b00218e7cc1 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -275,6 +275,8 @@ impl<'b> Resolver<'b> { self.structs.insert(item_def_id, field_names); } + ItemKind::Union(..) => panic!("`union` is not yet implemented"), + ItemKind::DefaultImpl(_, _) | ItemKind::Impl(..) => {} ItemKind::Trait(_, _, _, ref items) => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 5641a50ccaccf..b5cf680cc129c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1619,6 +1619,7 @@ impl<'a> Resolver<'a> { ItemKind::Enum(_, ref generics) | ItemKind::Ty(_, ref generics) | ItemKind::Struct(_, ref generics) | + ItemKind::Union(_, ref generics) | ItemKind::Fn(_, _, _, _, ref generics, _) => { self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| visit::walk_item(this, item)); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c0994ccb2acf9..fcb99444957c4 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1883,6 +1883,10 @@ pub enum ItemKind { /// /// E.g. `struct Foo { x: A }` Struct(VariantData, Generics), + /// A union definition (`union` or `pub union`). + /// + /// E.g. `union Foo { 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 { .. }` @@ -1919,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/config.rs b/src/libsyntax/config.rs index ff1ecd443717e..69a979176521b 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -180,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/fold.rs b/src/libsyntax/fold.rs index fad0b6f65a70d..7500bfe9caa80 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -885,6 +885,10 @@ pub fn noop_fold_item_kind(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/print/pprust.rs b/src/libsyntax/print/pprust.rs index 99c00789219bf..8563d27908db6 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1251,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)); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index b2d4799665956..efd9b027504f0 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -278,7 +278,8 @@ pub fn walk_item(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); From 663caa9ddf856c5e3a9612b1ac002c8d0646a3c2 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 28 Aug 2016 10:52:03 +0000 Subject: [PATCH 16/18] Remove inherent methods `Annotatable::attrs` and `Annotatable::fold_attrs`. --- src/libsyntax/ext/base.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 6ba3b92483fdd..43e190f5deb81 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) -> Annotatable { - self.map_attrs(|_| attrs) - } - pub fn expect_item(self) -> P { match self { Annotatable::Item(i) => i, From cdde06ea97ad7ef9718cc0896ab3989f11188da2 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 28 Aug 2016 11:18:58 +0000 Subject: [PATCH 17/18] Fix merge conflicts. --- src/librustc_typeck/check/intrinsic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index ed3e645eeebeb..d26de9b2a6c53 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -52,7 +52,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let i_n_tps = i_ty.generics.types.len(); if i_n_tps != n_tps { let span = match it.node { - hir::ForeignItemFn(_, ref generics) => generics.span().unwrap_or(it.span), + hir::ForeignItemFn(_, ref generics) => generics.span, hir::ForeignItemStatic(_, _) => it.span }; From 02f081c0b53cad0bcfe1d20ebb892f06ffa996ff Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 29 Aug 2016 11:14:25 +0000 Subject: [PATCH 18/18] Future proof `libsyntax_ext` for `union`. --- src/libsyntax_ext/deriving/bounds.rs | 1 + src/libsyntax_ext/deriving/clone.rs | 1 + src/libsyntax_ext/deriving/cmp/eq.rs | 1 + src/libsyntax_ext/deriving/cmp/ord.rs | 1 + src/libsyntax_ext/deriving/cmp/partial_eq.rs | 1 + src/libsyntax_ext/deriving/cmp/partial_ord.rs | 1 + src/libsyntax_ext/deriving/debug.rs | 1 + src/libsyntax_ext/deriving/decodable.rs | 1 + src/libsyntax_ext/deriving/default.rs | 1 + src/libsyntax_ext/deriving/encodable.rs | 1 + src/libsyntax_ext/deriving/generic/mod.rs | 3 +++ src/libsyntax_ext/deriving/hash.rs | 1 + src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs | 1 + .../run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs | 1 + 14 files changed, 16 insertions(+) diff --git a/src/libsyntax_ext/deriving/bounds.rs b/src/libsyntax_ext/deriving/bounds.rs index cfc98bf36871f..efb2fe5eb3b0f 100644 --- a/src/libsyntax_ext/deriving/bounds.rs +++ b/src/libsyntax_ext/deriving/bounds.rs @@ -40,6 +40,7 @@ pub fn expand_deriving_copy(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: true, methods: Vec::new(), associated_types: Vec::new(), }; diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index ce8ce2209d8c4..f1a3a1f41b14e 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -80,6 +80,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, additional_bounds: bounds, generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: vec![MethodDef { name: "clone", generics: LifetimeBounds::empty(), diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs index 2515435abeb9e..425a47a991bc4 100644 --- a/src/libsyntax_ext/deriving/cmp/eq.rs +++ b/src/libsyntax_ext/deriving/cmp/eq.rs @@ -50,6 +50,7 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: vec![MethodDef { name: "assert_receiver_is_total_eq", generics: LifetimeBounds::empty(), diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs index 31194b04fa6e4..6b2e36e63b657 100644 --- a/src/libsyntax_ext/deriving/cmp/ord.rs +++ b/src/libsyntax_ext/deriving/cmp/ord.rs @@ -32,6 +32,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: vec![MethodDef { name: "cmp", generics: LifetimeBounds::empty(), diff --git a/src/libsyntax_ext/deriving/cmp/partial_eq.rs b/src/libsyntax_ext/deriving/cmp/partial_eq.rs index f70e0cf4ac457..64b8829dad7b1 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_eq.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_eq.rs @@ -97,6 +97,7 @@ pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: methods, associated_types: Vec::new(), }; diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index 9e9b2f020622f..99d60c43c5457 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -88,6 +88,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, additional_bounds: vec![], generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: methods, associated_types: Vec::new(), }; diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index a31c695e36049..b974699003b97 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -35,6 +35,7 @@ pub fn expand_deriving_debug(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: vec![MethodDef { name: "fmt", generics: LifetimeBounds::empty(), diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs index f395f7bd0c4c4..22b9eb8e75445 100644 --- a/src/libsyntax_ext/deriving/decodable.rs +++ b/src/libsyntax_ext/deriving/decodable.rs @@ -62,6 +62,7 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: vec![MethodDef { name: "decode", generics: LifetimeBounds { diff --git a/src/libsyntax_ext/deriving/default.rs b/src/libsyntax_ext/deriving/default.rs index 449c1ff066b3b..b15fd2b49a655 100644 --- a/src/libsyntax_ext/deriving/default.rs +++ b/src/libsyntax_ext/deriving/default.rs @@ -32,6 +32,7 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: vec![MethodDef { name: "default", generics: LifetimeBounds::empty(), diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs index 940fdf037711f..a4074184b6e81 100644 --- a/src/libsyntax_ext/deriving/encodable.rs +++ b/src/libsyntax_ext/deriving/encodable.rs @@ -138,6 +138,7 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: vec!( MethodDef { name: "encode", diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index a8b682d81599a..5c636d43a7142 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -228,6 +228,9 @@ pub struct TraitDef<'a> { /// Is it an `unsafe` trait? pub is_unsafe: bool, + /// Can this trait be derived for unions? + pub supports_unions: bool, + pub methods: Vec>, pub associated_types: Vec<(ast::Ident, Ty<'a>)>, diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs index 81c8e7112dbd5..0941ebca868e3 100644 --- a/src/libsyntax_ext/deriving/hash.rs +++ b/src/libsyntax_ext/deriving/hash.rs @@ -36,6 +36,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, + supports_unions: false, methods: vec![MethodDef { name: "hash", generics: LifetimeBounds { diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs index 274e430bbea74..6b688b006bd4a 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs @@ -49,6 +49,7 @@ fn expand(cx: &mut ExtCtxt, generics: LifetimeBounds::empty(), associated_types: vec![], is_unsafe: false, + supports_unions: false, methods: vec![ MethodDef { name: "total_sum", diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs index 91b4b74797a83..c6174745bfc06 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs @@ -51,6 +51,7 @@ fn expand(cx: &mut ExtCtxt, generics: LifetimeBounds::empty(), associated_types: vec![], is_unsafe: false, + supports_unions: false, methods: vec![ MethodDef { name: "total_sum",