From 880262a2bcd6b3756a6ebd8438a87e26b64c6927 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 8 Mar 2017 02:50:13 +0300 Subject: Update syntax for `pub(restricted)` --- src/libsyntax/parse/parser.rs | 72 ++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 32 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6c566dab1d6..12e3c2ff95b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4605,7 +4605,7 @@ impl<'a> Parser<'a> { let mut attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let vis = self.parse_visibility(true)?; + let vis = self.parse_visibility()?; let defaultness = self.parse_defaultness()?; let (name, node) = if self.eat_keyword(keywords::Type) { let name = self.parse_ident()?; @@ -4936,7 +4936,7 @@ impl<'a> Parser<'a> { |p| { let attrs = p.parse_outer_attributes()?; let lo = p.span.lo; - let mut vis = p.parse_visibility(false)?; + let mut vis = p.parse_visibility()?; let ty_is_interpolated = p.token.is_interpolated() || p.look_ahead(1, |t| t.is_interpolated()); let mut ty = p.parse_ty()?; @@ -4993,38 +4993,46 @@ impl<'a> Parser<'a> { fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> { let attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let vis = self.parse_visibility(true)?; + let vis = self.parse_visibility()?; self.parse_single_struct_field(lo, vis, attrs) } - // If `allow_path` is false, just parse the `pub` in `pub(path)` (but still parse `pub(crate)`) - fn parse_visibility(&mut self, allow_path: bool) -> PResult<'a, Visibility> { - let pub_crate = |this: &mut Self| { - let span = this.prev_span; - this.expect(&token::CloseDelim(token::Paren))?; - Ok(Visibility::Crate(span)) - }; - + // Parse `pub`, `pub(crate)` and `pub(in path)` plus shortcuts + // `pub(self)` for `pub(in self)` and `pub(super)` for `pub(in super)`. + fn parse_visibility(&mut self) -> PResult<'a, Visibility> { if !self.eat_keyword(keywords::Pub) { - Ok(Visibility::Inherited) - } else if !allow_path { - // Look ahead to avoid eating the `(` in `pub(path)` while still parsing `pub(crate)` - if self.token == token::OpenDelim(token::Paren) && - self.look_ahead(1, |t| t.is_keyword(keywords::Crate)) { - self.bump(); self.bump(); - pub_crate(self) - } else { - Ok(Visibility::Public) - } - } else if !self.eat(&token::OpenDelim(token::Paren)) { - Ok(Visibility::Public) - } else if self.eat_keyword(keywords::Crate) { - pub_crate(self) - } else { - let path = self.parse_path(PathStyle::Mod)?.default_to_global(); - self.expect(&token::CloseDelim(token::Paren))?; - Ok(Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }) - } + return Ok(Visibility::Inherited) + } + + if self.check(&token::OpenDelim(token::Paren)) { + if self.look_ahead(1, |t| t.is_keyword(keywords::Crate)) { + // `pub(crate)` + self.bump(); // `(` + self.bump(); // `crate` + let vis = Visibility::Crate(self.prev_span); + self.expect(&token::CloseDelim(token::Paren))?; // `)` + return Ok(vis) + } else if self.look_ahead(1, |t| t.is_keyword(keywords::In)) { + // `pub(in path)` + self.bump(); // `(` + self.bump(); // `in` + let path = self.parse_path(PathStyle::Mod)?.default_to_global(); // `path` + let vis = Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; + self.expect(&token::CloseDelim(token::Paren))?; // `)` + return Ok(vis) + } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) && + self.look_ahead(1, |t| t.is_keyword(keywords::Super) || + t.is_keyword(keywords::SelfValue)) { + // `pub(self)` or `pub(super)` + self.bump(); // `(` + let path = self.parse_path(PathStyle::Mod)?.default_to_global(); // `super`/`self` + let vis = Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; + self.expect(&token::CloseDelim(token::Paren))?; // `)` + return Ok(vis) + } + } + + Ok(Visibility::Public) } /// Parse defaultness: DEFAULT or nothing @@ -5499,7 +5507,7 @@ impl<'a> Parser<'a> { let lo = self.span.lo; - let visibility = self.parse_visibility(true)?; + let visibility = self.parse_visibility()?; if self.eat_keyword(keywords::Use) { // USE ITEM @@ -5774,7 +5782,7 @@ impl<'a> Parser<'a> { fn parse_foreign_item(&mut self) -> PResult<'a, Option> { let attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let visibility = self.parse_visibility(true)?; + let visibility = self.parse_visibility()?; if self.check_keyword(keywords::Static) { // FOREIGN STATIC ITEM -- cgit 1.4.1-3-g733a5 From 32575a0487a2086ca7b15a0ca2565efc60bdc0c3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 8 Mar 2017 20:30:06 +0300 Subject: Give spans to individual path segments in AST --- src/librustc_resolve/lib.rs | 7 +++---- src/librustc_resolve/macros.rs | 5 ++++- src/libsyntax/ast.rs | 14 +++++++------- src/libsyntax/ext/build.rs | 19 ++++++++++++------- src/libsyntax/fold.rs | 3 ++- src/libsyntax/parse/mod.rs | 18 +++++++++++------- src/libsyntax/parse/parser.rs | 29 ++++++++++++++++++----------- src/libsyntax/std_inject.rs | 2 +- src/libsyntax/test.rs | 2 +- src/libsyntax_ext/concat_idents.rs | 2 +- 10 files changed, 60 insertions(+), 41 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d51ec268ec2..105af23d05c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3124,11 +3124,10 @@ impl<'a> Resolver<'a> { if ident.name == lookup_name && ns == namespace { if filter_fn(name_binding.def()) { // create the path - let span = name_binding.span; let mut segms = path_segments.clone(); - segms.push(ident.into()); + segms.push(ast::PathSegment::from_ident(ident, name_binding.span)); let path = Path { - span: span, + span: name_binding.span, segments: segms, }; // the entity is accessible in the following cases: @@ -3148,7 +3147,7 @@ impl<'a> Resolver<'a> { if let Some(module) = name_binding.module() { // form the path let mut path_segments = path_segments.clone(); - path_segments.push(ident.into()); + path_segments.push(ast::PathSegment::from_ident(ident, name_binding.span)); if !in_module_is_extern || name_binding.vis == ty::Visibility::Public { // add the module to the lookup diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 720d616e007..d81bdf17034 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -110,8 +110,11 @@ impl<'a> base::Resolver for Resolver<'a> { path.segments[0].identifier.name = keywords::CrateRoot.name(); let module = self.0.resolve_crate_var(ident.ctxt); if !module.is_local() { + let span = path.segments[0].span; path.segments.insert(1, match module.kind { - ModuleKind::Def(_, name) => ast::Ident::with_empty_ctxt(name).into(), + ModuleKind::Def(_, name) => ast::PathSegment::from_ident( + ast::Ident::with_empty_ctxt(name), span + ), _ => unreachable!(), }) } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9cc754cbf4d..adb7e8d101f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -134,7 +134,7 @@ impl Path { pub fn from_ident(s: Span, identifier: Ident) -> Path { Path { span: s, - segments: vec![identifier.into()], + segments: vec![PathSegment::from_ident(identifier, s)], } } @@ -159,6 +159,8 @@ impl Path { pub struct PathSegment { /// The identifier portion of this path segment. pub identifier: Ident, + /// Span of the segment identifier. + pub span: Span, /// Type/lifetime parameters attached to this path. They come in /// two flavors: `Path` and `Path(A,B) -> C`. Note that @@ -170,16 +172,14 @@ pub struct PathSegment { pub parameters: Option>, } -impl From for PathSegment { - fn from(id: Ident) -> Self { - PathSegment { identifier: id, parameters: None } - } -} - impl PathSegment { + pub fn from_ident(ident: Ident, span: Span) -> Self { + PathSegment { identifier: ident, span: span, parameters: None } + } pub fn crate_root() -> Self { PathSegment { identifier: keywords::CrateRoot.ident(), + span: DUMMY_SP, parameters: None, } } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index f8d4eff80b2..e0fb46ff5eb 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -38,11 +38,11 @@ pub trait AstBuilder { fn qpath(&self, self_type: P, trait_path: ast::Path, - ident: ast::Ident) + ident: ast::SpannedIdent) -> (ast::QSelf, ast::Path); fn qpath_all(&self, self_type: P, trait_path: ast::Path, - ident: ast::Ident, + ident: ast::SpannedIdent, lifetimes: Vec, types: Vec>, bindings: Vec) @@ -323,7 +323,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { segments.push(ast::PathSegment::crate_root()); } - segments.extend(idents.into_iter().map(Into::into)); + segments.extend(idents.into_iter().map(|i| ast::PathSegment::from_ident(i, sp))); let parameters = if lifetimes.is_empty() && types.is_empty() && bindings.is_empty() { None } else { @@ -333,7 +333,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> { bindings: bindings, }))) }; - segments.push(ast::PathSegment { identifier: last_identifier, parameters: parameters }); + segments.push(ast::PathSegment { + identifier: last_identifier, + span: sp, + parameters: parameters + }); ast::Path { span: sp, segments: segments, @@ -346,7 +350,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn qpath(&self, self_type: P, trait_path: ast::Path, - ident: ast::Ident) + ident: ast::SpannedIdent) -> (ast::QSelf, ast::Path) { self.qpath_all(self_type, trait_path, ident, vec![], vec![], vec![]) } @@ -357,7 +361,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn qpath_all(&self, self_type: P, trait_path: ast::Path, - ident: ast::Ident, + ident: ast::SpannedIdent, lifetimes: Vec, types: Vec>, bindings: Vec) @@ -369,7 +373,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> { bindings: bindings, }; path.segments.push(ast::PathSegment { - identifier: ident, + identifier: ident.node, + span: ident.span, parameters: Some(P(ast::PathParameters::AngleBracketed(parameters))), }); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 4242b0f8b98..665f48ab456 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -434,8 +434,9 @@ pub fn noop_fold_usize(i: usize, _: &mut T) -> usize { pub fn noop_fold_path(Path { segments, span }: Path, fld: &mut T) -> Path { Path { - segments: segments.move_map(|PathSegment {identifier, parameters}| PathSegment { + segments: segments.move_map(|PathSegment {identifier, span, parameters}| PathSegment { identifier: fld.fold_ident(identifier), + span: fld.new_span(span), parameters: parameters.map(|ps| ps.map(|ps| fld.fold_path_parameters(ps))), }), span: fld.new_span(span) diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index c00d2952b3b..88535f91379 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -617,13 +617,17 @@ mod tests { Span {lo: BytePos(a), hi: BytePos(b), expn_id: NO_EXPANSION} } + fn str2seg(s: &str, lo: u32, hi: u32) -> ast::PathSegment { + ast::PathSegment::from_ident(Ident::from_str(s), sp(lo, hi)) + } + #[test] fn path_exprs_1() { assert!(string_to_expr("a".to_string()) == P(ast::Expr{ id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 1), - segments: vec![Ident::from_str("a").into()], + segments: vec![str2seg("a", 0, 1)], }), span: sp(0, 1), attrs: ThinVec::new(), @@ -637,8 +641,8 @@ mod tests { node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 6), segments: vec![ast::PathSegment::crate_root(), - Ident::from_str("a").into(), - Ident::from_str("b").into()] + str2seg("a", 2, 3), + str2seg("b", 5, 6)] }), span: sp(0, 6), attrs: ThinVec::new(), @@ -744,7 +748,7 @@ mod tests { id: ast::DUMMY_NODE_ID, node:ast::ExprKind::Path(None, ast::Path{ span: sp(7, 8), - segments: vec![Ident::from_str("d").into()], + segments: vec![str2seg("d", 7, 8)], }), span:sp(7,8), attrs: ThinVec::new(), @@ -761,7 +765,7 @@ mod tests { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span:sp(0,1), - segments: vec![Ident::from_str("b").into()], + segments: vec![str2seg("b", 0, 1)], }), span: sp(0,1), attrs: ThinVec::new()})), @@ -802,7 +806,7 @@ mod tests { ty: P(ast::Ty{id: ast::DUMMY_NODE_ID, node: ast::TyKind::Path(None, ast::Path{ span:sp(10,13), - segments: vec![Ident::from_str("i32").into()], + segments: vec![str2seg("i32", 10, 13)], }), span:sp(10,13) }), @@ -844,7 +848,7 @@ mod tests { node: ast::ExprKind::Path(None, ast::Path{ span:sp(17,18), - segments: vec![Ident::from_str("b").into()], + segments: vec![str2seg("b", 17, 18)], }), span: sp(17,18), attrs: ThinVec::new()})), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6c566dab1d6..002f1359b6f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -27,7 +27,7 @@ use ast::Local; use ast::MacStmtStyle; use ast::Mac_; use ast::{MutTy, Mutability}; -use ast::{Pat, PatKind}; +use ast::{Pat, PatKind, PathSegment}; use ast::{PolyTraitRef, QSelf}; use ast::{Stmt, StmtKind}; use ast::{VariantData, StructField}; @@ -1811,7 +1811,7 @@ impl<'a> Parser<'a> { }; if is_global { - segments.insert(0, ast::PathSegment::crate_root()); + segments.insert(0, PathSegment::crate_root()); } // Assemble the span. @@ -1829,11 +1829,12 @@ impl<'a> Parser<'a> { /// - `a::b::c` /// - `a::b::c(V) -> W` /// - `a::b::c(V)` - pub fn parse_path_segments_without_colons(&mut self) -> PResult<'a, Vec> { + pub fn parse_path_segments_without_colons(&mut self) -> PResult<'a, Vec> { let mut segments = Vec::new(); loop { // First, parse an identifier. let identifier = self.parse_path_segment_ident()?; + let ident_span = self.prev_span; if self.check(&token::ModSep) && self.look_ahead(1, |t| *t == token::Lt) { self.bump(); @@ -1881,7 +1882,11 @@ impl<'a> Parser<'a> { }; // Assemble and push the result. - segments.push(ast::PathSegment { identifier: identifier, parameters: parameters }); + segments.push(PathSegment { + identifier: identifier, + span: ident_span, + parameters: parameters + }); // Continue only if we see a `::` if !self.eat(&token::ModSep) { @@ -1892,15 +1897,16 @@ impl<'a> Parser<'a> { /// Examples: /// - `a::b::::c` - pub fn parse_path_segments_with_colons(&mut self) -> PResult<'a, Vec> { + pub fn parse_path_segments_with_colons(&mut self) -> PResult<'a, Vec> { let mut segments = Vec::new(); loop { // First, parse an identifier. let identifier = self.parse_path_segment_ident()?; + let ident_span = self.prev_span; // If we do not see a `::`, stop. if !self.eat(&token::ModSep) { - segments.push(identifier.into()); + segments.push(PathSegment::from_ident(identifier, ident_span)); return Ok(segments); } @@ -1909,8 +1915,9 @@ impl<'a> Parser<'a> { // Consumed `a::b::<`, go look for types let (lifetimes, types, bindings) = self.parse_generic_args()?; self.expect_gt()?; - segments.push(ast::PathSegment { + segments.push(PathSegment { identifier: identifier, + span: ident_span, parameters: ast::AngleBracketedParameterData { lifetimes: lifetimes, types: types, @@ -1924,7 +1931,7 @@ impl<'a> Parser<'a> { } } else { // Consumed `a::`, go look for `b` - segments.push(identifier.into()); + segments.push(PathSegment::from_ident(identifier, ident_span)); } } } @@ -1932,14 +1939,14 @@ impl<'a> Parser<'a> { /// Examples: /// - `a::b::c` pub fn parse_path_segments_without_types(&mut self) - -> PResult<'a, Vec> { + -> PResult<'a, Vec> { let mut segments = Vec::new(); loop { // First, parse an identifier. let identifier = self.parse_path_segment_ident()?; // Assemble and push the result. - segments.push(identifier.into()); + segments.push(PathSegment::from_ident(identifier, self.prev_span)); // If we do not see a `::` or see `::{`/`::*`, stop. if !self.check(&token::ModSep) || self.is_import_coupler() { @@ -5902,7 +5909,7 @@ impl<'a> Parser<'a> { // `{foo, bar}`, `::{foo, bar}`, `*`, or `::*`. self.eat(&token::ModSep); let prefix = ast::Path { - segments: vec![ast::PathSegment::crate_root()], + segments: vec![PathSegment::crate_root()], span: mk_sp(lo, self.span.hi), }; let view_path_kind = if self.eat(&token::BinOp(token::Star)) { diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 4a2dfaf6124..2192d203cdc 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -82,7 +82,7 @@ pub fn maybe_inject_crates_ref(sess: &ParseSess, vis: ast::Visibility::Inherited, node: ast::ItemKind::Use(P(codemap::dummy_spanned(ast::ViewPathGlob(ast::Path { segments: ["{{root}}", name, "prelude", "v1"].into_iter().map(|name| { - ast::Ident::from_str(name).into() + ast::PathSegment::from_ident(ast::Ident::from_str(name), DUMMY_SP) }).collect(), span: span, })))), diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index dd2756cd2b2..e052d2cda3a 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -580,7 +580,7 @@ fn nospan(t: T) -> codemap::Spanned { fn path_node(ids: Vec) -> ast::Path { ast::Path { span: DUMMY_SP, - segments: ids.into_iter().map(Into::into).collect(), + segments: ids.into_iter().map(|id| ast::PathSegment::from_ident(id, DUMMY_SP)).collect(), } } diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs index 1fc1bdff593..dc4b8eb24cd 100644 --- a/src/libsyntax_ext/concat_idents.rs +++ b/src/libsyntax_ext/concat_idents.rs @@ -61,7 +61,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, fn path(&self) -> ast::Path { ast::Path { span: self.span, - segments: vec![self.ident.into()], + segments: vec![ast::PathSegment::from_ident(self.ident, self.span)], } } } -- cgit 1.4.1-3-g733a5 From d95c5437222fd63d7b12676bc7916dbeb720f131 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Fri, 17 Feb 2017 15:12:47 -0800 Subject: Add catch expr to AST and disallow catch as a struct name --- src/librustc/hir/lowering.rs | 37 +++++++++++++++++++++--- src/libsyntax/ast.rs | 2 ++ src/libsyntax/feature_gate.rs | 6 ++++ src/libsyntax/fold.rs | 1 + src/libsyntax/parse/parser.rs | 35 ++++++++++++++++++++++ src/libsyntax/print/pprust.rs | 5 ++++ src/libsyntax/symbol.rs | 3 +- src/libsyntax/visit.rs | 3 ++ src/test/compile-fail/catch-empty-struct-name.rs | 15 ++++++++++ src/test/compile-fail/catch-enum-variant.rs | 17 +++++++++++ src/test/compile-fail/catch-struct-name.rs | 15 ++++++++++ src/test/compile-fail/catch-tuple-struct-name.rs | 15 ++++++++++ src/test/compile-fail/feature-gate-catch_expr.rs | 17 +++++++++++ src/test/run-pass/catch-expr.rs | 30 +++++++++++++++++++ 14 files changed, 196 insertions(+), 5 deletions(-) create mode 100644 src/test/compile-fail/catch-empty-struct-name.rs create mode 100644 src/test/compile-fail/catch-enum-variant.rs create mode 100644 src/test/compile-fail/catch-struct-name.rs create mode 100644 src/test/compile-fail/catch-tuple-struct-name.rs create mode 100644 src/test/compile-fail/feature-gate-catch_expr.rs create mode 100644 src/test/run-pass/catch-expr.rs (limited to 'src/libsyntax/parse') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index aa6614b0af4..d92eaee6f0c 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -84,6 +84,7 @@ pub struct LoweringContext<'a> { trait_impls: BTreeMap>, trait_default_impl: BTreeMap, + catch_scopes: Vec, loop_scopes: Vec, is_in_loop_condition: bool, @@ -123,6 +124,7 @@ pub fn lower_crate(sess: &Session, trait_impls: BTreeMap::new(), trait_default_impl: BTreeMap::new(), exported_macros: Vec::new(), + catch_scopes: Vec::new(), loop_scopes: Vec::new(), is_in_loop_condition: false, type_def_lifetime_params: DefIdMap(), @@ -261,6 +263,21 @@ impl<'a> LoweringContext<'a> { span } + fn with_catch_scope(&mut self, catch_id: NodeId, f: F) -> T + where F: FnOnce(&mut LoweringContext) -> T + { + let len = self.catch_scopes.len(); + self.catch_scopes.push(catch_id); + + let result = f(self); + assert_eq!(len + 1, self.catch_scopes.len(), + "catch scopes should be added and removed in stack order"); + + self.catch_scopes.pop().unwrap(); + + result + } + fn with_loop_scope(&mut self, loop_id: NodeId, f: F) -> T where F: FnOnce(&mut LoweringContext) -> T { @@ -295,15 +312,17 @@ impl<'a> LoweringContext<'a> { result } - fn with_new_loop_scopes(&mut self, f: F) -> T + fn with_new_scopes(&mut self, f: F) -> T where F: FnOnce(&mut LoweringContext) -> T { let was_in_loop_condition = self.is_in_loop_condition; self.is_in_loop_condition = false; + let catch_scopes = mem::replace(&mut self.catch_scopes, Vec::new()); let loop_scopes = mem::replace(&mut self.loop_scopes, Vec::new()); let result = f(self); - mem::replace(&mut self.loop_scopes, loop_scopes); + self.catch_scopes = catch_scopes; + self.loop_scopes = loop_scopes; self.is_in_loop_condition = was_in_loop_condition; @@ -1065,7 +1084,7 @@ impl<'a> LoweringContext<'a> { self.record_body(value, None)) } ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { - self.with_new_loop_scopes(|this| { + self.with_new_scopes(|this| { let body = this.lower_block(body); let body = this.expr_block(body, ThinVec::new()); let body_id = this.record_body(body, Some(decl)); @@ -1665,13 +1684,17 @@ impl<'a> LoweringContext<'a> { this.lower_opt_sp_ident(opt_ident), hir::LoopSource::Loop)) } + ExprKind::Catch(ref body) => { + // FIXME(cramertj): Add catch to HIR + self.with_catch_scope(e.id, |this| hir::ExprBlock(this.lower_block(body))) + } ExprKind::Match(ref expr, ref arms) => { hir::ExprMatch(P(self.lower_expr(expr)), arms.iter().map(|x| self.lower_arm(x)).collect(), hir::MatchSource::Normal) } ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => { - self.with_new_loop_scopes(|this| { + self.with_new_scopes(|this| { this.with_parent_def(e.id, |this| { let expr = this.lower_expr(body); hir::ExprClosure(this.lower_capture_clause(capture_clause), @@ -2069,6 +2092,12 @@ impl<'a> LoweringContext<'a> { // Err(err) => #[allow(unreachable_code)] // return Carrier::from_error(From::from(err)), // } + + // FIXME(cramertj): implement breaking to catch + if !self.catch_scopes.is_empty() { + bug!("`?` in catch scopes is unimplemented") + } + let unstable_span = self.allow_internal_unstable("?", e.span); // Carrier::translate() diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 981667337d5..f4e5fd0783b 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -935,6 +935,8 @@ pub enum ExprKind { Closure(CaptureBy, P, P, Span), /// A block (`{ ... }`) Block(P), + /// A catch block (`catch { ... }`) + Catch(P), /// An assignment (`a = foo()`) Assign(P, P), diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e7bf16eae9e..15913d56d16 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -339,6 +339,9 @@ declare_features! ( // `extern "x86-interrupt" fn()` (active, abi_x86_interrupt, "1.17.0", Some(40180)), + + // Allows the `catch {...}` expression + (active, catch_expr, "1.17.0", Some(31436)), ); declare_features! ( @@ -1287,6 +1290,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } } + ast::ExprKind::Catch(_) => { + gate_feature_post!(&self, catch_expr, e.span, "`catch` expression is experimental"); + } _ => {} } visit::walk_expr(self, e); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index fb4eb19be2b..fe543280264 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1268,6 +1268,7 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu }; } ExprKind::Try(ex) => ExprKind::Try(folder.fold_expr(ex)), + ExprKind::Catch(body) => ExprKind::Catch(folder.fold_block(body)), }, id: folder.new_id(id), span: folder.new_span(span), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6446d38e5ef..c0ee778b7ee 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -602,6 +602,12 @@ impl<'a> Parser<'a> { } } + pub fn error_if_typename_is_catch(&mut self, ident: ast::Ident) { + if ident.name == keywords::Catch.name() { + self.span_err(self.span, "cannot use `catch` as the name of a type"); + } + } + /// Check if the next token is `tok`, and return `true` if so. /// /// This method will automatically add `tok` to `expected_tokens` if `tok` is not @@ -2273,6 +2279,11 @@ impl<'a> Parser<'a> { BlockCheckMode::Unsafe(ast::UserProvided), attrs); } + if self.is_catch_expr() { + assert!(self.eat_keyword(keywords::Catch)); + let lo = self.prev_span.lo; + return self.parse_catch_expr(lo, attrs); + } if self.eat_keyword(keywords::Return) { if self.token.can_begin_expr() { let e = self.parse_expr()?; @@ -3092,6 +3103,16 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(span_lo, hi, ExprKind::Loop(body, opt_ident), attrs)) } + /// Parse a `catch {...}` expression (`catch` token already eaten) + pub fn parse_catch_expr(&mut self, span_lo: BytePos, mut attrs: ThinVec) + -> PResult<'a, P> + { + let (iattrs, body) = self.parse_inner_attrs_and_block()?; + attrs.extend(iattrs); + let hi = body.span.hi; + Ok(self.mk_expr(span_lo, hi, ExprKind::Catch(body), attrs)) + } + // `match` token already eaten fn parse_match_expr(&mut self, mut attrs: ThinVec) -> PResult<'a, P> { let match_span = self.prev_span; @@ -3699,6 +3720,14 @@ impl<'a> Parser<'a> { }) } + fn is_catch_expr(&mut self) -> bool { + self.token.is_keyword(keywords::Catch) && + self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) && + + // prevent `while catch {} {}`, `if catch {} {} else {}`, etc. + !self.restrictions.contains(Restrictions::RESTRICTION_NO_STRUCT_LITERAL) + } + fn is_union_item(&self) -> bool { self.token.is_keyword(keywords::Union) && self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) @@ -4875,6 +4904,8 @@ impl<'a> Parser<'a> { /// Parse struct Foo { ... } fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; + self.error_if_typename_is_catch(class_name); + let mut generics = self.parse_generics()?; // There is a special case worth noting here, as reported in issue #17904. @@ -4924,6 +4955,8 @@ impl<'a> Parser<'a> { /// Parse union Foo { ... } fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; + self.error_if_typename_is_catch(class_name); + let mut generics = self.parse_generics()?; let vdata = if self.token.is_keyword(keywords::Where) { @@ -5440,6 +5473,7 @@ impl<'a> Parser<'a> { let struct_def; let mut disr_expr = None; let ident = self.parse_ident()?; + self.error_if_typename_is_catch(ident); if self.check(&token::OpenDelim(token::Brace)) { // Parse a struct variant. all_nullary = false; @@ -5481,6 +5515,7 @@ impl<'a> Parser<'a> { /// Parse an "enum" declaration fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> { let id = self.parse_ident()?; + self.error_if_typename_is_catch(id); let mut generics = self.parse_generics()?; generics.where_clause = self.parse_where_clause()?; self.expect(&token::OpenDelim(token::Brace))?; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 3efadbd00d1..c44153d0d32 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2279,6 +2279,11 @@ impl<'a> State<'a> { self.print_expr(e)?; word(&mut self.s, "?")? } + ast::ExprKind::Catch(ref blk) => { + self.head("catch")?; + space(&mut self.s)?; + self.print_block_with_attrs(&blk, attrs)? + } } self.ann.post(self, NodeExpr(expr))?; self.end() diff --git a/src/libsyntax/symbol.rs b/src/libsyntax/symbol.rs index c278171aa10..6642c60d256 100644 --- a/src/libsyntax/symbol.rs +++ b/src/libsyntax/symbol.rs @@ -221,9 +221,10 @@ declare_keywords! { (53, Default, "default") (54, StaticLifetime, "'static") (55, Union, "union") + (56, Catch, "catch") // A virtual keyword that resolves to the crate root when used in a lexical scope. - (56, CrateRoot, "{{root}}") + (57, CrateRoot, "{{root}}") } // If an interner exists in TLS, return it. Otherwise, prepare a fresh one. diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index ee7dd18247b..a5333f3bb6a 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -779,6 +779,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::Try(ref subexpression) => { visitor.visit_expr(subexpression) } + ExprKind::Catch(ref body) => { + visitor.visit_block(body) + } } visitor.visit_expr_post(expression) diff --git a/src/test/compile-fail/catch-empty-struct-name.rs b/src/test/compile-fail/catch-empty-struct-name.rs new file mode 100644 index 00000000000..257cb802cc0 --- /dev/null +++ b/src/test/compile-fail/catch-empty-struct-name.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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. + +#![allow(non_camel_case_types)] +#![allow(dead_code)] +#![feature(catch_expr)] + +struct catch; //~ ERROR cannot use `catch` as the name of a type diff --git a/src/test/compile-fail/catch-enum-variant.rs b/src/test/compile-fail/catch-enum-variant.rs new file mode 100644 index 00000000000..7aa162750d1 --- /dev/null +++ b/src/test/compile-fail/catch-enum-variant.rs @@ -0,0 +1,17 @@ +// Copyright 2017 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. + +#![allow(non_camel_case_types)] +#![allow(dead_code)] +#![feature(catch_expr)] + +enum Enum { + catch {} //~ ERROR cannot use `catch` as the name of a type +} diff --git a/src/test/compile-fail/catch-struct-name.rs b/src/test/compile-fail/catch-struct-name.rs new file mode 100644 index 00000000000..63661ccf607 --- /dev/null +++ b/src/test/compile-fail/catch-struct-name.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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. + +#![allow(non_camel_case_types)] +#![allow(dead_code)] +#![feature(catch_expr)] + +struct catch {} //~ ERROR cannot use `catch` as the name of a type \ No newline at end of file diff --git a/src/test/compile-fail/catch-tuple-struct-name.rs b/src/test/compile-fail/catch-tuple-struct-name.rs new file mode 100644 index 00000000000..1a8866d8543 --- /dev/null +++ b/src/test/compile-fail/catch-tuple-struct-name.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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. + +#![allow(non_camel_case_types)] +#![allow(dead_code)] +#![feature(catch_expr)] + +struct catch(); //~ ERROR cannot use `catch` as the name of a type diff --git a/src/test/compile-fail/feature-gate-catch_expr.rs b/src/test/compile-fail/feature-gate-catch_expr.rs new file mode 100644 index 00000000000..8a1a5ceae89 --- /dev/null +++ b/src/test/compile-fail/feature-gate-catch_expr.rs @@ -0,0 +1,17 @@ +// Copyright 2017 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. + +pub fn main() { + let catch_result = catch { //~ ERROR `catch` expression is experimental + let x = 5; + x + }; + assert_eq!(catch_result, 5); +} diff --git a/src/test/run-pass/catch-expr.rs b/src/test/run-pass/catch-expr.rs new file mode 100644 index 00000000000..c70b6100efe --- /dev/null +++ b/src/test/run-pass/catch-expr.rs @@ -0,0 +1,30 @@ +// Copyright 2017 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(catch_expr)] + +pub fn main() { + let catch_result = catch { + let x = 5; + x + }; + assert_eq!(catch_result, 5); + + let mut catch = true; + while catch { catch = false; } + assert_eq!(catch, false); + + catch = if catch { false } else { true }; + assert_eq!(catch, true); + + match catch { + _ => {} + }; +} -- cgit 1.4.1-3-g733a5 From ea4e8b0a81171d4d6c28a61fa0d1c4d74837bb65 Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Fri, 3 Mar 2017 14:41:07 -0800 Subject: Temporarily prefix catch block with do keyword --- src/libsyntax/parse/parser.rs | 18 +++++------------- src/libsyntax/parse/token.rs | 1 + src/libsyntax/print/pprust.rs | 2 +- src/test/compile-fail/catch-empty-struct-name.rs | 15 --------------- src/test/compile-fail/catch-enum-variant.rs | 17 ----------------- src/test/compile-fail/catch-struct-name.rs | 15 --------------- src/test/compile-fail/catch-tuple-struct-name.rs | 15 --------------- src/test/compile-fail/feature-gate-catch_expr.rs | 2 +- src/test/run-pass/catch-expr.rs | 4 +++- 9 files changed, 11 insertions(+), 78 deletions(-) delete mode 100644 src/test/compile-fail/catch-empty-struct-name.rs delete mode 100644 src/test/compile-fail/catch-enum-variant.rs delete mode 100644 src/test/compile-fail/catch-struct-name.rs delete mode 100644 src/test/compile-fail/catch-tuple-struct-name.rs (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c0ee778b7ee..252b4ec4660 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -602,12 +602,6 @@ impl<'a> Parser<'a> { } } - pub fn error_if_typename_is_catch(&mut self, ident: ast::Ident) { - if ident.name == keywords::Catch.name() { - self.span_err(self.span, "cannot use `catch` as the name of a type"); - } - } - /// Check if the next token is `tok`, and return `true` if so. /// /// This method will automatically add `tok` to `expected_tokens` if `tok` is not @@ -2280,6 +2274,7 @@ impl<'a> Parser<'a> { attrs); } if self.is_catch_expr() { + assert!(self.eat_keyword(keywords::Do)); assert!(self.eat_keyword(keywords::Catch)); let lo = self.prev_span.lo; return self.parse_catch_expr(lo, attrs); @@ -3103,7 +3098,7 @@ impl<'a> Parser<'a> { Ok(self.mk_expr(span_lo, hi, ExprKind::Loop(body, opt_ident), attrs)) } - /// Parse a `catch {...}` expression (`catch` token already eaten) + /// Parse a `do catch {...}` expression (`do catch` token already eaten) pub fn parse_catch_expr(&mut self, span_lo: BytePos, mut attrs: ThinVec) -> PResult<'a, P> { @@ -3721,8 +3716,9 @@ impl<'a> Parser<'a> { } fn is_catch_expr(&mut self) -> bool { - self.token.is_keyword(keywords::Catch) && - self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) && + self.token.is_keyword(keywords::Do) && + self.look_ahead(1, |t| t.is_keyword(keywords::Catch)) && + self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace)) && // prevent `while catch {} {}`, `if catch {} {} else {}`, etc. !self.restrictions.contains(Restrictions::RESTRICTION_NO_STRUCT_LITERAL) @@ -4904,7 +4900,6 @@ impl<'a> Parser<'a> { /// Parse struct Foo { ... } fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; - self.error_if_typename_is_catch(class_name); let mut generics = self.parse_generics()?; @@ -4955,7 +4950,6 @@ impl<'a> Parser<'a> { /// Parse union Foo { ... } fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; - self.error_if_typename_is_catch(class_name); let mut generics = self.parse_generics()?; @@ -5473,7 +5467,6 @@ impl<'a> Parser<'a> { let struct_def; let mut disr_expr = None; let ident = self.parse_ident()?; - self.error_if_typename_is_catch(ident); if self.check(&token::OpenDelim(token::Brace)) { // Parse a struct variant. all_nullary = false; @@ -5515,7 +5508,6 @@ impl<'a> Parser<'a> { /// Parse an "enum" declaration fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> { let id = self.parse_ident()?; - self.error_if_typename_is_catch(id); let mut generics = self.parse_generics()?; generics.where_clause = self.parse_where_clause()?; self.expect(&token::OpenDelim(token::Brace))?; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 5b65aac92b8..25601f2420e 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -86,6 +86,7 @@ fn ident_can_begin_expr(ident: ast::Ident) -> bool { !ident_token.is_any_keyword() || ident_token.is_path_segment_keyword() || [ + keywords::Do.name(), keywords::Box.name(), keywords::Break.name(), keywords::Continue.name(), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index c44153d0d32..83753f398a3 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2280,7 +2280,7 @@ impl<'a> State<'a> { word(&mut self.s, "?")? } ast::ExprKind::Catch(ref blk) => { - self.head("catch")?; + self.head("do catch")?; space(&mut self.s)?; self.print_block_with_attrs(&blk, attrs)? } diff --git a/src/test/compile-fail/catch-empty-struct-name.rs b/src/test/compile-fail/catch-empty-struct-name.rs deleted file mode 100644 index 257cb802cc0..00000000000 --- a/src/test/compile-fail/catch-empty-struct-name.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017 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. - -#![allow(non_camel_case_types)] -#![allow(dead_code)] -#![feature(catch_expr)] - -struct catch; //~ ERROR cannot use `catch` as the name of a type diff --git a/src/test/compile-fail/catch-enum-variant.rs b/src/test/compile-fail/catch-enum-variant.rs deleted file mode 100644 index 7aa162750d1..00000000000 --- a/src/test/compile-fail/catch-enum-variant.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017 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. - -#![allow(non_camel_case_types)] -#![allow(dead_code)] -#![feature(catch_expr)] - -enum Enum { - catch {} //~ ERROR cannot use `catch` as the name of a type -} diff --git a/src/test/compile-fail/catch-struct-name.rs b/src/test/compile-fail/catch-struct-name.rs deleted file mode 100644 index 63661ccf607..00000000000 --- a/src/test/compile-fail/catch-struct-name.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017 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. - -#![allow(non_camel_case_types)] -#![allow(dead_code)] -#![feature(catch_expr)] - -struct catch {} //~ ERROR cannot use `catch` as the name of a type \ No newline at end of file diff --git a/src/test/compile-fail/catch-tuple-struct-name.rs b/src/test/compile-fail/catch-tuple-struct-name.rs deleted file mode 100644 index 1a8866d8543..00000000000 --- a/src/test/compile-fail/catch-tuple-struct-name.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017 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. - -#![allow(non_camel_case_types)] -#![allow(dead_code)] -#![feature(catch_expr)] - -struct catch(); //~ ERROR cannot use `catch` as the name of a type diff --git a/src/test/compile-fail/feature-gate-catch_expr.rs b/src/test/compile-fail/feature-gate-catch_expr.rs index 8a1a5ceae89..5568a5cf0aa 100644 --- a/src/test/compile-fail/feature-gate-catch_expr.rs +++ b/src/test/compile-fail/feature-gate-catch_expr.rs @@ -9,7 +9,7 @@ // except according to those terms. pub fn main() { - let catch_result = catch { //~ ERROR `catch` expression is experimental + let catch_result = do catch { //~ ERROR `catch` expression is experimental let x = 5; x }; diff --git a/src/test/run-pass/catch-expr.rs b/src/test/run-pass/catch-expr.rs index c70b6100efe..a9b28a534a3 100644 --- a/src/test/run-pass/catch-expr.rs +++ b/src/test/run-pass/catch-expr.rs @@ -10,8 +10,10 @@ #![feature(catch_expr)] +struct catch {} + pub fn main() { - let catch_result = catch { + let catch_result = do catch { let x = 5; x }; -- cgit 1.4.1-3-g733a5 From 460bf55f8a649a7f19680df2ac67dbeb936f8700 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 6 Mar 2017 06:45:28 +0000 Subject: Cleanup. --- src/libsyntax/ext/tt/macro_parser.rs | 2 +- src/libsyntax/parse/parser.rs | 21 ++++++++++----------- 2 files changed, 11 insertions(+), 12 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index b9cb3d82d4f..6385d206a0c 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -488,7 +488,7 @@ pub fn parse(sess: &ParseSess, tts: TokenStream, ms: &[TokenTree], directory: Op fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { match name { "tt" => { - return token::NtTT(panictry!(p.parse_token_tree())); + return token::NtTT(p.parse_token_tree()); } _ => {} } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6446d38e5ef..9872afd27b7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -891,7 +891,7 @@ impl<'a> Parser<'a> { self.parse_seq_to_before_tokens(kets, SeqSep::none(), - |p| p.parse_token_tree(), + |p| Ok(p.parse_token_tree()), |mut e| handler.cancel(&mut e)); } @@ -1267,7 +1267,7 @@ impl<'a> Parser<'a> { break; } token::OpenDelim(token::Brace) => { - self.parse_token_tree()?; + self.parse_token_tree(); break; } _ => self.bump(), @@ -2101,10 +2101,10 @@ impl<'a> Parser<'a> { fn expect_delimited_token_tree(&mut self) -> PResult<'a, (token::DelimToken, ThinTokenStream)> { match self.token { - token::OpenDelim(delim) => self.parse_token_tree().map(|tree| match tree { - TokenTree::Delimited(_, delimited) => (delim, delimited.stream().into()), + token::OpenDelim(delim) => match self.parse_token_tree() { + TokenTree::Delimited(_, delimited) => Ok((delim, delimited.stream().into())), _ => unreachable!(), - }), + }, _ => Err(self.fatal("expected open delimiter")), } } @@ -2643,24 +2643,23 @@ impl<'a> Parser<'a> { } /// parse a single token tree from the input. - pub fn parse_token_tree(&mut self) -> PResult<'a, TokenTree> { + pub fn parse_token_tree(&mut self) -> TokenTree { match self.token { token::OpenDelim(..) => { let frame = mem::replace(&mut self.token_cursor.frame, self.token_cursor.stack.pop().unwrap()); self.span = frame.span; self.bump(); - return Ok(TokenTree::Delimited(frame.span, Delimited { + TokenTree::Delimited(frame.span, Delimited { delim: frame.delim, tts: frame.tree_cursor.original_stream().into(), - })); + }) }, token::CloseDelim(_) | token::Eof => unreachable!(), _ => { let token = mem::replace(&mut self.token, token::Underscore); - let res = Ok(TokenTree::Token(self.span, token)); self.bump(); - res + TokenTree::Token(self.prev_span, token) } } } @@ -2670,7 +2669,7 @@ impl<'a> Parser<'a> { pub fn parse_all_token_trees(&mut self) -> PResult<'a, Vec> { let mut tts = Vec::new(); while self.token != token::Eof { - tts.push(self.parse_token_tree()?); + tts.push(self.parse_token_tree()); } Ok(tts) } -- cgit 1.4.1-3-g733a5 From 68c1cc68b44bb987ec57251bc457a55292515d1d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 3 Mar 2017 09:23:59 +0000 Subject: Refactor `Attribute` to use `Path` and `TokenStream` instead of `MetaItem`. --- src/librustc/hir/check_attr.rs | 11 +- src/librustc/hir/lowering.rs | 2 +- src/librustc/lint/context.rs | 4 +- src/librustc/middle/stability.rs | 4 +- src/librustc/traits/error_reporting.rs | 2 +- .../calculate_svh/svh_visitor.rs | 55 +--- src/librustc_incremental/persist/dirty_clean.rs | 8 +- src/librustc_lint/builtin.rs | 8 +- src/librustc_lint/lib.rs | 1 + src/librustc_lint/unused.rs | 5 +- src/librustc_metadata/creader.rs | 8 +- src/librustc_metadata/cstore.rs | 9 +- src/librustc_passes/ast_validation.rs | 4 +- src/librustc_resolve/lib.rs | 5 +- src/librustc_resolve/macros.rs | 43 ++- src/librustc_save_analysis/external_data.rs | 4 +- src/librustc_save_analysis/lib.rs | 5 +- src/librustc_trans/assert_module_sources.rs | 2 +- src/librustdoc/clean/mod.rs | 21 +- src/librustdoc/html/render.rs | 4 +- src/librustdoc/test.rs | 14 +- src/librustdoc/visit_ast.rs | 2 +- src/libsyntax/ast.rs | 9 +- src/libsyntax/attr.rs | 306 ++++++++++++++++++--- src/libsyntax/config.rs | 8 +- src/libsyntax/ext/derive.rs | 4 +- src/libsyntax/ext/expand.rs | 42 +-- src/libsyntax/ext/quote.rs | 14 +- src/libsyntax/feature_gate.rs | 28 +- src/libsyntax/fold.rs | 7 +- src/libsyntax/lib.rs | 10 + src/libsyntax/parse/attr.rs | 16 +- src/libsyntax/parse/mod.rs | 131 ++++++--- src/libsyntax/parse/parser.rs | 44 +-- src/libsyntax/parse/token.rs | 4 +- src/libsyntax/print/pprust.rs | 100 ++++--- src/libsyntax/std_inject.rs | 8 +- src/libsyntax/tokenstream.rs | 2 +- src/libsyntax_ext/deriving/custom.rs | 8 +- src/libsyntax_ext/deriving/generic/mod.rs | 2 +- src/libsyntax_ext/proc_macro_registrar.rs | 12 +- 41 files changed, 614 insertions(+), 362 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 6f5f548aa78..54ae9472140 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -120,11 +120,12 @@ impl<'a> CheckAttrVisitor<'a> { } fn check_attribute(&self, attr: &ast::Attribute, target: Target) { - let name: &str = &attr.name().as_str(); - match name { - "inline" => self.check_inline(attr, target), - "repr" => self.check_repr(attr, target), - _ => (), + if let Some(name) = attr.name() { + match &*name.as_str() { + "inline" => self.check_inline(attr, target), + "repr" => self.check_repr(attr, target), + _ => (), + } } } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index aa6614b0af4..a5c82130675 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1277,7 +1277,7 @@ impl<'a> LoweringContext<'a> { let attrs = self.lower_attrs(&i.attrs); let mut vis = self.lower_visibility(&i.vis); if let ItemKind::MacroDef(ref tts) = i.node { - if i.attrs.iter().any(|attr| attr.name() == "macro_export") { + if i.attrs.iter().any(|attr| attr.path == "macro_export") { self.exported_macros.push(hir::MacroDef { name: name, attrs: attrs, id: i.id, span: i.span, body: tts.clone().into(), }); diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 9279f24a57a..65e2fec0b8b 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -402,14 +402,14 @@ pub fn gather_attrs(attrs: &[ast::Attribute]) -> Vec Vec> { let mut out = vec![]; - let level = match Level::from_str(&attr.name().as_str()) { + let level = match attr.name().and_then(|name| Level::from_str(&name.as_str())) { None => return out, Some(lvl) => lvl, }; + let meta = unwrap_or!(attr.meta(), return out); attr::mark_used(attr); - let meta = &attr.value; let metas = if let Some(metas) = meta.meta_item_list() { metas } else { diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index baa22d70614..1fb53714025 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -197,7 +197,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { } else { // Emit errors for non-staged-api crates. for attr in attrs { - let tag = attr.name(); + let tag = unwrap_or!(attr.name(), continue); if tag == "unstable" || tag == "stable" || tag == "rustc_deprecated" { attr::mark_used(attr); self.tcx.sess.span_err(attr.span(), "stability attributes may not be used \ @@ -402,7 +402,7 @@ impl<'a, 'tcx> Index<'tcx> { let mut is_staged_api = false; for attr in &krate.attrs { - if attr.name() == "stable" || attr.name() == "unstable" { + if attr.path == "stable" || attr.path == "unstable" { is_staged_api = true; break } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 0e5c786cd8d..27525d550ff 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -274,7 +274,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .filter(|a| a.check_name("rustc_on_unimplemented")) .next() { - let err_sp = item.meta().span.substitute_dummy(span); + let err_sp = item.span.substitute_dummy(span); let trait_str = self.tcx.item_path_str(trait_ref.def_id); if let Some(istring) = item.value_str() { let istring = &*istring.as_str(); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index d0eedcac0c0..fac49b29598 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -18,16 +18,15 @@ use syntax::abi::Abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; use syntax::parse::token; -use syntax::symbol::{Symbol, InternedString}; +use syntax::symbol::InternedString; use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos}; use syntax::tokenstream; use rustc::hir; use rustc::hir::*; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; -use rustc::hir::intravisit as visit; +use rustc::hir::intravisit::{self as visit, Visitor}; use rustc::ty::TyCtxt; -use rustc_data_structures::fnv; use std::hash::{Hash, Hasher}; use super::def_path_hash::DefPathHashes; @@ -559,7 +558,7 @@ macro_rules! hash_span { }); } -impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> { +impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> visit::NestedVisitorMap<'this, 'tcx> { if self.hash_bodies { visit::NestedVisitorMap::OnlyBodies(&self.tcx.hir) @@ -960,50 +959,24 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { } } - fn hash_meta_item(&mut self, meta_item: &ast::MetaItem) { - debug!("hash_meta_item: st={:?}", self.st); - - // ignoring span information, it doesn't matter here - self.hash_discriminant(&meta_item.node); - meta_item.name.as_str().len().hash(self.st); - meta_item.name.as_str().hash(self.st); - - match meta_item.node { - ast::MetaItemKind::Word => {} - ast::MetaItemKind::NameValue(ref lit) => saw_lit(lit).hash(self.st), - ast::MetaItemKind::List(ref items) => { - // Sort subitems so the hash does not depend on their order - let indices = self.indices_sorted_by(&items, |p| { - (p.name().map(Symbol::as_str), fnv::hash(&p.literal().map(saw_lit))) - }); - items.len().hash(self.st); - for (index, &item_index) in indices.iter().enumerate() { - index.hash(self.st); - let nested_meta_item: &ast::NestedMetaItemKind = &items[item_index].node; - self.hash_discriminant(nested_meta_item); - match *nested_meta_item { - ast::NestedMetaItemKind::MetaItem(ref meta_item) => { - self.hash_meta_item(meta_item); - } - ast::NestedMetaItemKind::Literal(ref lit) => { - saw_lit(lit).hash(self.st); - } - } - } - } - } - } - pub fn hash_attributes(&mut self, attributes: &[ast::Attribute]) { debug!("hash_attributes: st={:?}", self.st); let indices = self.indices_sorted_by(attributes, |attr| attr.name()); for i in indices { let attr = &attributes[i]; - if !attr.is_sugared_doc && - !IGNORED_ATTRIBUTES.contains(&&*attr.value.name().as_str()) { + match attr.name() { + Some(name) if IGNORED_ATTRIBUTES.contains(&&*name.as_str()) => continue, + _ => {} + }; + if !attr.is_sugared_doc { SawAttribute(attr.style).hash(self.st); - self.hash_meta_item(&attr.value); + for segment in &attr.path.segments { + SawIdent(segment.identifier.name.as_str()).hash(self.st); + } + for tt in attr.tokens.trees() { + self.hash_token_tree(&tt); + } } } } diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 156f8b9e7c4..929249df0b1 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -104,9 +104,9 @@ pub struct DirtyCleanVisitor<'a, 'tcx:'a> { impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { fn dep_node(&self, attr: &Attribute, def_id: DefId) -> DepNode { - for item in attr.meta_item_list().unwrap_or(&[]) { + for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.check_name(LABEL) { - let value = expect_associated_value(self.tcx, item); + let value = expect_associated_value(self.tcx, &item); match DepNode::from_label_string(&value.as_str(), def_id) { Ok(def_id) => return def_id, Err(()) => { @@ -331,9 +331,9 @@ fn check_config(tcx: TyCtxt, attr: &Attribute) -> bool { debug!("check_config(attr={:?})", attr); let config = &tcx.sess.parse_sess.config; debug!("check_config: config={:?}", config); - for item in attr.meta_item_list().unwrap_or(&[]) { + for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.check_name(CFG) { - let value = expect_associated_value(tcx, item); + let value = expect_associated_value(tcx, &item); debug!("check_config: searching for cfg {:?}", value); return config.contains(&(value, None)); } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 58336f939d1..f0276f90f27 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -312,7 +312,7 @@ impl MissingDoc { } } - let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc"); + let has_doc = attrs.iter().any(|a| a.is_value_str() && a.check_name("doc")); if !has_doc { cx.span_lint(MISSING_DOCS, sp, @@ -635,7 +635,7 @@ impl LintPass for DeprecatedAttr { impl EarlyLintPass for DeprecatedAttr { fn check_attribute(&mut self, cx: &EarlyContext, attr: &ast::Attribute) { - let name = attr.name(); + let name = unwrap_or!(attr.name(), return); for &&(n, _, ref g) in &self.depr_attrs { if name == n { if let &AttributeGate::Gated(Stability::Deprecated(link), @@ -1121,8 +1121,8 @@ impl LintPass for UnstableFeatures { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnstableFeatures { fn check_attribute(&mut self, ctx: &LateContext, attr: &ast::Attribute) { - if attr.meta().check_name("feature") { - if let Some(items) = attr.meta().meta_item_list() { + if attr.check_name("feature") { + if let Some(items) = attr.meta_item_list() { for item in items { ctx.span_lint(UNSTABLE_FEATURES, item.span(), "unstable feature"); } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 443a219928f..05dbbc09870 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -38,6 +38,7 @@ #![feature(slice_patterns)] #![feature(staged_api)] +#[macro_use] extern crate syntax; #[macro_use] extern crate rustc; diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index f9b7c685876..abba8afd9da 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -269,6 +269,7 @@ impl LintPass for UnusedAttributes { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes { fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) { debug!("checking attribute: {:?}", attr); + let name = unwrap_or!(attr.name(), return); // Note that check_name() marks the attribute as used if it matches. for &(ref name, ty, _) in BUILTIN_ATTRIBUTES { @@ -294,13 +295,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes { cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute"); // Is it a builtin attribute that must be used at the crate level? let known_crate = BUILTIN_ATTRIBUTES.iter() - .find(|&&(name, ty, _)| attr.name() == name && ty == AttributeType::CrateLevel) + .find(|&&(builtin, ty, _)| name == builtin && ty == AttributeType::CrateLevel) .is_some(); // Has a plugin registered this attribute as one which must be used at // the crate level? let plugin_crate = plugin_attributes.iter() - .find(|&&(ref x, t)| attr.name() == &**x && AttributeType::CrateLevel == t) + .find(|&&(ref x, t)| name == &**x && AttributeType::CrateLevel == t) .is_some(); if known_crate || plugin_crate { let msg = match attr.style { diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 49dcffb4830..9f5ce00f408 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -973,9 +973,11 @@ impl<'a> CrateLoader<'a> { impl<'a> CrateLoader<'a> { pub fn preprocess(&mut self, krate: &ast::Crate) { - for attr in krate.attrs.iter().filter(|m| m.name() == "link_args") { - if let Some(linkarg) = attr.value_str() { - self.cstore.add_used_link_args(&linkarg.as_str()); + for attr in &krate.attrs { + if attr.path == "link_args" { + if let Some(linkarg) = attr.value_str() { + self.cstore.add_used_link_args(&linkarg.as_str()); + } } } } diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index bb30245df5f..17a6a706e0a 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -269,9 +269,12 @@ impl CrateMetadata { } pub fn is_staged_api(&self) -> bool { - self.get_item_attrs(CRATE_DEF_INDEX) - .iter() - .any(|attr| attr.name() == "stable" || attr.name() == "unstable") + for attr in self.get_item_attrs(CRATE_DEF_INDEX) { + if attr.path == "stable" || attr.path == "unstable" { + return true; + } + } + false } pub fn is_allocator(&self) -> bool { diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 0933fdfd357..8c45a666945 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -241,12 +241,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { 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"); - if let Some(attr) = - item.attrs.iter().find(|attr| attr.name() == "warn_directory_ownership") { + if item.attrs.iter().any(|attr| attr.check_name("warn_directory_ownership")) { let lint = lint::builtin::LEGACY_DIRECTORY_OWNERSHIP; let msg = "cannot declare a new module at this location"; self.session.add_lint(lint, item.id, item.span, msg.to_string()); - attr::mark_used(attr); } } ItemKind::Union(ref vdata, _) => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0958748ed09..c3e471650a3 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3360,8 +3360,9 @@ impl<'a> Resolver<'a> { if self.proc_macro_enabled { return; } for attr in attrs { - let maybe_binding = self.builtin_macros.get(&attr.name()).cloned().or_else(|| { - let ident = Ident::with_empty_ctxt(attr.name()); + let name = unwrap_or!(attr.name(), continue); + let maybe_binding = self.builtin_macros.get(&name).cloned().or_else(|| { + let ident = Ident::with_empty_ctxt(name); self.resolve_lexical_macro_path_segment(ident, MacroNS, None).ok() }); diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 7ad122d1c31..9e1dcd1bc35 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -30,6 +30,7 @@ use syntax::feature_gate::{self, emit_feature_err, GateIssue}; use syntax::fold::{self, Folder}; use syntax::ptr::P; use syntax::symbol::{Symbol, keywords}; +use syntax::tokenstream::TokenStream; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::{Span, DUMMY_SP}; @@ -176,12 +177,14 @@ impl<'a> base::Resolver for Resolver<'a> { fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec) -> Option { for i in 0..attrs.len() { + let name = unwrap_or!(attrs[i].name(), continue); + if self.session.plugin_attributes.borrow().iter() - .any(|&(ref attr_nm, _)| attrs[i].name() == &**attr_nm) { + .any(|&(ref attr_nm, _)| name == &**attr_nm) { attr::mark_known(&attrs[i]); } - match self.builtin_macros.get(&attrs[i].name()).cloned() { + match self.builtin_macros.get(&name).cloned() { Some(binding) => match *binding.get_macro(self) { MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => { return Some(attrs.remove(i)) @@ -194,9 +197,11 @@ impl<'a> base::Resolver for Resolver<'a> { // Check for legacy derives for i in 0..attrs.len() { - if attrs[i].name() == "derive" { + let name = unwrap_or!(attrs[i].name(), continue); + + if name == "derive" { let mut traits = match attrs[i].meta_item_list() { - Some(traits) if !traits.is_empty() => traits.to_owned(), + Some(traits) => traits, _ => continue, }; @@ -213,18 +218,11 @@ impl<'a> base::Resolver for Resolver<'a> { if traits.is_empty() { attrs.remove(i); } else { - attrs[i].value = ast::MetaItem { - name: attrs[i].name(), - span: attrs[i].span, - node: ast::MetaItemKind::List(traits), - }; + attrs[i].tokens = ast::MetaItemKind::List(traits).tokens(attrs[i].span); } return Some(ast::Attribute { - value: ast::MetaItem { - name: legacy_name, - span: span, - node: ast::MetaItemKind::Word, - }, + path: ast::Path::from_ident(span, Ident::with_empty_ctxt(legacy_name)), + tokens: TokenStream::empty(), id: attr::mk_attr_id(), style: ast::AttrStyle::Outer, is_sugared_doc: false, @@ -270,19 +268,20 @@ impl<'a> Resolver<'a> { } }; - let (attr_name, path) = { - let attr = attr.as_ref().unwrap(); - (attr.name(), ast::Path::from_ident(attr.span, Ident::with_empty_ctxt(attr.name()))) - }; - let mut determined = true; + let path = attr.as_ref().unwrap().path.clone(); + let mut determinacy = Determinacy::Determined; match self.resolve_macro_to_def(scope, &path, MacroKind::Attr, force) { Ok(def) => return Ok(def), - Err(Determinacy::Undetermined) => determined = false, + Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined, Err(Determinacy::Determined) if force => return Err(Determinacy::Determined), Err(Determinacy::Determined) => {} } + let attr_name = match path.segments.len() { + 1 => path.segments[0].identifier.name, + _ => return Err(determinacy), + }; for &(name, span) in traits { let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); match self.resolve_macro(scope, &path, MacroKind::Derive, force) { @@ -304,12 +303,12 @@ impl<'a> Resolver<'a> { } return Err(Determinacy::Undetermined); }, - Err(Determinacy::Undetermined) => determined = false, + Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined, Err(Determinacy::Determined) => {} } } - Err(if determined { Determinacy::Determined } else { Determinacy::Undetermined }) + Err(determinacy) } fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index 41658dc5b1b..f038c2dc298 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -14,7 +14,6 @@ use rustc::ty::TyCtxt; use syntax::ast::{self, NodeId}; use syntax::codemap::CodeMap; use syntax::print::pprust; -use syntax::symbol::Symbol; use syntax_pos::Span; use data::{self, Visibility, SigElement}; @@ -77,10 +76,9 @@ impl Lower for Vec { type Target = Vec; fn lower(self, tcx: TyCtxt) -> Vec { - let doc = Symbol::intern("doc"); self.into_iter() // Only retain real attributes. Doc comments are lowered separately. - .filter(|attr| attr.name() != doc) + .filter(|attr| attr.path != "doc") .map(|mut attr| { // Remove the surrounding '#[..]' or '#![..]' of the pretty printed // attribute. First normalize all inner attribute (#![..]) to outer diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 111c8370be2..90ee19198c9 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -54,7 +54,7 @@ use std::path::{Path, PathBuf}; use syntax::ast::{self, NodeId, PatKind, Attribute, CRATE_NODE_ID}; use syntax::parse::lexer::comments::strip_doc_comment_decoration; use syntax::parse::token; -use syntax::symbol::{Symbol, keywords}; +use syntax::symbol::keywords; use syntax::visit::{self, Visitor}; use syntax::print::pprust::{ty_to_string, arg_to_string}; use syntax::codemap::MacroAttribute; @@ -829,11 +829,10 @@ impl<'a> Visitor<'a> for PathCollector { } fn docs_for_attrs(attrs: &[Attribute]) -> String { - let doc = Symbol::intern("doc"); let mut result = String::new(); for attr in attrs { - if attr.name() == doc { + if attr.check_name("doc") { if let Some(val) = attr.value_str() { if attr.is_sugared_doc { result.push_str(&strip_doc_comment_decoration(&val.as_str())); diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs index 7a41f834109..8528482c785 100644 --- a/src/librustc_trans/assert_module_sources.rs +++ b/src/librustc_trans/assert_module_sources.rs @@ -113,7 +113,7 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { } fn field(&self, attr: &ast::Attribute, name: &str) -> ast::Name { - for item in attr.meta_item_list().unwrap_or(&[]) { + for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.check_name(name) { if let Some(value) = item.value_str() { return value; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1294296840e..660fa647882 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -39,12 +39,11 @@ use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc::hir; +use std::{mem, slice, vec}; use std::path::PathBuf; use std::rc::Rc; -use std::slice; use std::sync::Arc; use std::u32; -use std::mem; use core::DocContext; use doctree; @@ -472,12 +471,12 @@ impl Clean for doctree::Module { pub struct ListAttributesIter<'a> { attrs: slice::Iter<'a, ast::Attribute>, - current_list: slice::Iter<'a, ast::NestedMetaItem>, + current_list: vec::IntoIter, name: &'a str } impl<'a> Iterator for ListAttributesIter<'a> { - type Item = &'a ast::NestedMetaItem; + type Item = ast::NestedMetaItem; fn next(&mut self) -> Option { if let Some(nested) = self.current_list.next() { @@ -485,9 +484,9 @@ impl<'a> Iterator for ListAttributesIter<'a> { } for attr in &mut self.attrs { - if let Some(ref list) = attr.meta_item_list() { + if let Some(list) = attr.meta_item_list() { if attr.check_name(self.name) { - self.current_list = list.iter(); + self.current_list = list.into_iter(); if let Some(nested) = self.current_list.next() { return Some(nested); } @@ -508,7 +507,7 @@ impl AttributesExt for [ast::Attribute] { fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> { ListAttributesIter { attrs: self.iter(), - current_list: [].iter(), + current_list: Vec::new().into_iter(), name: name } } @@ -519,7 +518,7 @@ pub trait NestedAttributesExt { fn has_word(self, &str) -> bool; } -impl<'a, I: IntoIterator> NestedAttributesExt for I { +impl> NestedAttributesExt for I { fn has_word(self, word: &str) -> bool { self.into_iter().any(|attr| attr.is_word() && attr.check_name(word)) } @@ -2596,9 +2595,9 @@ impl Clean> for doctree::Import { // #[doc(no_inline)] attribute is present. // Don't inline doc(hidden) imports so they can be stripped at a later stage. let denied = self.vis != hir::Public || self.attrs.iter().any(|a| { - a.name() == "doc" && match a.meta_item_list() { - Some(l) => attr::list_contains_name(l, "no_inline") || - attr::list_contains_name(l, "hidden"), + a.name().unwrap() == "doc" && match a.meta_item_list() { + Some(l) => attr::list_contains_name(&l, "no_inline") || + attr::list_contains_name(&l, "hidden"), None => false, } }); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 44f71d89529..130a4526bf7 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2620,11 +2620,11 @@ fn render_attributes(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result { let mut attrs = String::new(); for attr in &it.attrs.other_attrs { - let name = attr.name(); + let name = attr.name().unwrap(); if !ATTRIBUTE_WHITELIST.contains(&&name.as_str()[..]) { continue; } - if let Some(s) = render_attribute(attr.meta()) { + if let Some(s) = render_attribute(&attr.meta().unwrap()) { attrs.push_str(&format!("#[{}]\n", s)); } } diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index c1ecc241b7b..f6b7a07bdae 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -137,13 +137,13 @@ fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions { attrs: Vec::new(), }; - let attrs = krate.attrs.iter() - .filter(|a| a.check_name("doc")) - .filter_map(|a| a.meta_item_list()) - .flat_map(|l| l) - .filter(|a| a.check_name("test")) - .filter_map(|a| a.meta_item_list()) - .flat_map(|l| l); + let test_attrs: Vec<_> = krate.attrs.iter() + .filter(|a| a.check_name("doc")) + .flat_map(|a| a.meta_item_list().unwrap_or_else(Vec::new)) + .filter(|a| a.check_name("test")) + .collect(); + let attrs = test_attrs.iter().flat_map(|a| a.meta_item_list().unwrap_or(&[])); + for attr in attrs { if attr.check_name("no_crate_inject") { opts.no_crate_inject = true; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index b80de3cc505..4a909f8e2a9 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -376,7 +376,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { if item.vis == hir::Public && self.inside_public_path { let please_inline = item.attrs.iter().any(|item| { match item.meta_item_list() { - Some(list) if item.check_name("doc") => { + Some(ref 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 981667337d5..5deb91ef53a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -116,6 +116,12 @@ pub struct Path { pub segments: Vec, } +impl<'a> PartialEq<&'a str> for Path { + fn eq(&self, string: &&'a str) -> bool { + self.segments.len() == 1 && self.segments[0].identifier.name == *string + } +} + impl fmt::Debug for Path { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "path({})", pprust::path_to_string(self)) @@ -1679,7 +1685,8 @@ pub struct AttrId(pub usize); pub struct Attribute { pub id: AttrId, pub style: AttrStyle, - pub value: MetaItem, + pub path: Path, + pub tokens: TokenStream, pub is_sugared_doc: bool, pub span: Span, } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 096657a6e7a..68f1f690a62 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -15,20 +15,24 @@ pub use self::ReprAttr::*; pub use self::IntType::*; use ast; -use ast::{AttrId, Attribute, Name}; +use ast::{AttrId, Attribute, Name, Ident}; use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; -use ast::{Lit, Expr, Item, Local, Stmt, StmtKind}; +use ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind}; use codemap::{Spanned, spanned, dummy_spanned, mk_sp}; use syntax_pos::{Span, BytePos, DUMMY_SP}; use errors::Handler; use feature_gate::{Features, GatedCfg}; use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; -use parse::ParseSess; +use parse::parser::Parser; +use parse::{self, ParseSess, PResult}; +use parse::token::{self, Token}; use ptr::P; use symbol::Symbol; +use tokenstream::{TokenStream, TokenTree, Delimited}; use util::ThinVec; use std::cell::{RefCell, Cell}; +use std::iter; thread_local! { static USED_ATTRS: RefCell> = RefCell::new(Vec::new()); @@ -185,26 +189,38 @@ impl NestedMetaItem { impl Attribute { pub fn check_name(&self, name: &str) -> bool { - let matches = self.name() == name; + let matches = self.path == name; if matches { mark_used(self); } matches } - pub fn name(&self) -> Name { self.meta().name() } + pub fn name(&self) -> Option { + match self.path.segments.len() { + 1 => Some(self.path.segments[0].identifier.name), + _ => None, + } + } pub fn value_str(&self) -> Option { - self.meta().value_str() + self.meta().and_then(|meta| meta.value_str()) } - pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { - self.meta().meta_item_list() + pub fn meta_item_list(&self) -> Option> { + match self.meta() { + Some(MetaItem { node: MetaItemKind::List(list), .. }) => Some(list), + _ => None + } } - pub fn is_word(&self) -> bool { self.meta().is_word() } + pub fn is_word(&self) -> bool { + self.path.segments.len() == 1 && self.tokens.is_empty() + } - pub fn span(&self) -> Span { self.meta().span } + pub fn span(&self) -> Span { + self.span + } pub fn is_meta_item_list(&self) -> bool { self.meta_item_list().is_some() @@ -225,7 +241,7 @@ impl MetaItem { match self.node { MetaItemKind::NameValue(ref v) => { match v.node { - ast::LitKind::Str(ref s, _) => Some((*s).clone()), + LitKind::Str(ref s, _) => Some((*s).clone()), _ => None, } }, @@ -264,8 +280,35 @@ impl MetaItem { impl Attribute { /// Extract the MetaItem from inside this Attribute. - pub fn meta(&self) -> &MetaItem { - &self.value + pub fn meta(&self) -> Option { + let mut tokens = self.tokens.trees().peekable(); + Some(MetaItem { + name: match self.path.segments.len() { + 1 => self.path.segments[0].identifier.name, + _ => return None, + }, + node: if let Some(node) = MetaItemKind::from_tokens(&mut tokens) { + if tokens.peek().is_some() { + return None; + } + node + } else { + return None; + }, + span: self.span, + }) + } + + pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> { + if self.path.segments.len() > 1 { + sess.span_diagnostic.span_err(self.path.span, "expected ident, found path"); + } + + Ok(MetaItem { + name: self.path.segments.last().unwrap().identifier.name, + node: Parser::new(sess, self.tokens.clone(), None, false).parse_meta_item_kind()?, + span: self.span, + }) } /// Convert self to a normal #[doc="foo"] comment, if it is a @@ -293,7 +336,7 @@ impl Attribute { /* Constructors */ pub fn mk_name_value_item_str(name: Name, value: Symbol) -> MetaItem { - let value_lit = dummy_spanned(ast::LitKind::Str(value, ast::StrStyle::Cooked)); + let value_lit = dummy_spanned(LitKind::Str(value, ast::StrStyle::Cooked)); mk_spanned_name_value_item(DUMMY_SP, name, value_lit) } @@ -348,7 +391,8 @@ pub fn mk_spanned_attr_inner(sp: Span, id: AttrId, item: MetaItem) -> Attribute Attribute { id: id, style: ast::AttrStyle::Inner, - value: item, + path: ast::Path::from_ident(item.span, ast::Ident::with_empty_ctxt(item.name)), + tokens: item.node.tokens(item.span), is_sugared_doc: false, span: sp, } @@ -365,7 +409,8 @@ pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute Attribute { id: id, style: ast::AttrStyle::Outer, - value: item, + path: ast::Path::from_ident(item.span, ast::Ident::with_empty_ctxt(item.name)), + tokens: item.node.tokens(item.span), is_sugared_doc: false, span: sp, } @@ -374,32 +419,25 @@ pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, lo: BytePos, hi: BytePos) -> Attribute { let style = doc_comment_style(&text.as_str()); - let lit = spanned(lo, hi, ast::LitKind::Str(text, ast::StrStyle::Cooked)); + let lit = spanned(lo, hi, LitKind::Str(text, ast::StrStyle::Cooked)); Attribute { id: id, style: style, - value: MetaItem { - span: mk_sp(lo, hi), - name: Symbol::intern("doc"), - node: MetaItemKind::NameValue(lit), - }, + path: ast::Path::from_ident(mk_sp(lo, hi), ast::Ident::from_str("doc")), + tokens: MetaItemKind::NameValue(lit).tokens(mk_sp(lo, hi)), is_sugared_doc: true, span: mk_sp(lo, hi), } } pub fn list_contains_name(items: &[NestedMetaItem], name: &str) -> bool { - debug!("attr::list_contains_name (name={})", name); items.iter().any(|item| { - debug!(" testing: {:?}", item.name()); item.check_name(name) }) } pub fn contains_name(attrs: &[Attribute], name: &str) -> bool { - debug!("attr::contains_name (name={})", name); attrs.iter().any(|item| { - debug!(" testing: {}", item.name()); item.check_name(name) }) } @@ -452,8 +490,14 @@ pub enum InlineAttr { /// Determine what `#[inline]` attribute is present in `attrs`, if any. pub fn find_inline_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> InlineAttr { attrs.iter().fold(InlineAttr::None, |ia, attr| { - match attr.value.node { - _ if attr.value.name != "inline" => ia, + if attr.path != "inline" { + return ia; + } + let meta = match attr.meta() { + Some(meta) => meta.node, + None => return ia, + }; + match meta { MetaItemKind::Word => { mark_used(attr); InlineAttr::Hint @@ -574,14 +618,15 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, let mut rustc_depr: Option = None; 'outer: for attr in attrs_iter { - let tag = attr.name(); - if tag != "rustc_deprecated" && tag != "unstable" && tag != "stable" { + if attr.path != "rustc_deprecated" && attr.path != "unstable" && attr.path != "stable" { continue // not a stability level } mark_used(attr); - if let Some(metas) = attr.meta_item_list() { + let meta = attr.meta(); + if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta { + let meta = meta.as_ref().unwrap(); let get = |meta: &MetaItem, item: &mut Option| { if item.is_some() { handle_errors(diagnostic, meta.span, AttrError::MultipleItem(meta.name())); @@ -596,7 +641,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, } }; - match &*tag.as_str() { + match &*meta.name.as_str() { "rustc_deprecated" => { if rustc_depr.is_some() { span_err!(diagnostic, item_sp, E0540, @@ -772,7 +817,7 @@ fn find_deprecation_generic<'a, I>(diagnostic: &Handler, let mut depr: Option = None; 'outer: for attr in attrs_iter { - if attr.name() != "deprecated" { + if attr.path != "deprecated" { continue } @@ -847,8 +892,8 @@ pub fn find_deprecation(diagnostic: &Handler, attrs: &[Attribute], /// structure layout, and `packed` to remove padding. pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec { let mut acc = Vec::new(); - match attr.value.node { - ast::MetaItemKind::List(ref items) if attr.value.name == "repr" => { + if attr.path == "repr" { + if let Some(items) = attr.meta_item_list() { mark_used(attr); for item in items { if !item.is_meta_item() { @@ -883,8 +928,6 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec } } } - // Not a "repr" hint: ignore. - _ => { } } acc } @@ -931,6 +974,195 @@ impl IntType { } } +impl MetaItem { + fn tokens(&self) -> TokenStream { + let ident = TokenTree::Token(self.span, Token::Ident(Ident::with_empty_ctxt(self.name))); + TokenStream::concat(vec![ident.into(), self.node.tokens(self.span)]) + } + + fn from_tokens(tokens: &mut iter::Peekable) -> Option + where I: Iterator, + { + let (mut span, name) = match tokens.next() { + Some(TokenTree::Token(span, Token::Ident(ident))) => (span, ident.name), + _ => return None, + }; + let node = match MetaItemKind::from_tokens(tokens) { + Some(node) => node, + _ => return None, + }; + if let Some(last_span) = node.last_span() { + span.hi = last_span.hi; + } + Some(MetaItem { name: name, span: span, node: node }) + } +} + +impl MetaItemKind { + fn last_span(&self) -> Option { + match *self { + MetaItemKind::Word => None, + MetaItemKind::List(ref list) => list.last().map(NestedMetaItem::span), + MetaItemKind::NameValue(ref lit) => Some(lit.span), + } + } + + pub fn tokens(&self, span: Span) -> TokenStream { + match *self { + MetaItemKind::Word => TokenStream::empty(), + MetaItemKind::NameValue(ref lit) => { + TokenStream::concat(vec![TokenTree::Token(span, Token::Eq).into(), lit.tokens()]) + } + MetaItemKind::List(ref list) => { + let mut tokens = Vec::new(); + for (i, item) in list.iter().enumerate() { + if i > 0 { + tokens.push(TokenTree::Token(span, Token::Comma).into()); + } + tokens.push(item.node.tokens()); + } + TokenTree::Delimited(span, Delimited { + delim: token::Paren, + tts: TokenStream::concat(tokens).into(), + }).into() + } + } + } + + fn from_tokens(tokens: &mut iter::Peekable) -> Option + where I: Iterator, + { + let delimited = match tokens.peek().cloned() { + Some(TokenTree::Token(_, token::Eq)) => { + tokens.next(); + return if let Some(TokenTree::Token(span, token)) = tokens.next() { + LitKind::from_token(token) + .map(|lit| MetaItemKind::NameValue(Spanned { node: lit, span: span })) + } else { + None + }; + } + Some(TokenTree::Delimited(_, ref delimited)) if delimited.delim == token::Paren => { + tokens.next(); + delimited.stream() + } + _ => return Some(MetaItemKind::Word), + }; + + let mut tokens = delimited.into_trees().peekable(); + let mut result = Vec::new(); + while let Some(..) = tokens.peek() { + match NestedMetaItemKind::from_tokens(&mut tokens) { + Some(item) => result.push(Spanned { span: item.span(), node: item }), + None => return None, + } + match tokens.next() { + None | Some(TokenTree::Token(_, Token::Comma)) => {} + _ => return None, + } + } + Some(MetaItemKind::List(result)) + } +} + +impl NestedMetaItemKind { + fn span(&self) -> Span { + match *self { + NestedMetaItemKind::MetaItem(ref item) => item.span, + NestedMetaItemKind::Literal(ref lit) => lit.span, + } + } + + fn tokens(&self) -> TokenStream { + match *self { + NestedMetaItemKind::MetaItem(ref item) => item.tokens(), + NestedMetaItemKind::Literal(ref lit) => lit.tokens(), + } + } + + fn from_tokens(tokens: &mut iter::Peekable) -> Option + where I: Iterator, + { + if let Some(TokenTree::Token(span, token)) = tokens.peek().cloned() { + if let Some(node) = LitKind::from_token(token) { + tokens.next(); + return Some(NestedMetaItemKind::Literal(Spanned { node: node, span: span })); + } + } + + MetaItem::from_tokens(tokens).map(NestedMetaItemKind::MetaItem) + } +} + +impl Lit { + fn tokens(&self) -> TokenStream { + TokenTree::Token(self.span, self.node.token()).into() + } +} + +impl LitKind { + fn token(&self) -> Token { + use std::ascii; + + match *self { + LitKind::Str(string, ast::StrStyle::Cooked) => { + let mut escaped = String::new(); + for ch in string.as_str().chars() { + escaped.extend(ch.escape_unicode()); + } + Token::Literal(token::Lit::Str_(Symbol::intern(&escaped)), None) + } + LitKind::Str(string, ast::StrStyle::Raw(n)) => { + Token::Literal(token::Lit::StrRaw(string, n), None) + } + LitKind::ByteStr(ref bytes) => { + let string = bytes.iter().cloned().flat_map(ascii::escape_default) + .map(Into::::into).collect::(); + Token::Literal(token::Lit::ByteStr(Symbol::intern(&string)), None) + } + LitKind::Byte(byte) => { + let string: String = ascii::escape_default(byte).map(Into::::into).collect(); + Token::Literal(token::Lit::Byte(Symbol::intern(&string)), None) + } + LitKind::Char(ch) => { + let string: String = ch.escape_default().map(Into::::into).collect(); + Token::Literal(token::Lit::Char(Symbol::intern(&string)), None) + } + LitKind::Int(n, ty) => { + let suffix = match ty { + ast::LitIntType::Unsigned(ty) => Some(Symbol::intern(ty.ty_to_string())), + ast::LitIntType::Signed(ty) => Some(Symbol::intern(ty.ty_to_string())), + ast::LitIntType::Unsuffixed => None, + }; + Token::Literal(token::Lit::Integer(Symbol::intern(&n.to_string())), suffix) + } + LitKind::Float(symbol, ty) => { + Token::Literal(token::Lit::Float(symbol), Some(Symbol::intern(ty.ty_to_string()))) + } + LitKind::FloatUnsuffixed(symbol) => Token::Literal(token::Lit::Float(symbol), None), + LitKind::Bool(value) => Token::Ident(Ident::with_empty_ctxt(Symbol::intern(match value { + true => "true", + false => "false", + }))), + } + } + + fn from_token(token: Token) -> Option { + match token { + Token::Ident(ident) if ident.name == "true" => Some(LitKind::Bool(true)), + Token::Ident(ident) if ident.name == "false" => Some(LitKind::Bool(false)), + Token::Literal(lit, suf) => { + let (suffix_illegal, result) = parse::lit_token(lit, suf, None); + if suffix_illegal && suf.is_some() { + return None; + } + result + } + _ => None, + } + } +} + pub trait HasAttrs: Sized { fn attrs(&self) -> &[ast::Attribute]; fn map_attrs) -> Vec>(self, f: F) -> Self; diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index ea12a31770f..2591a576669 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -109,7 +109,8 @@ impl<'a> StripUnconfigured<'a> { self.process_cfg_attr(ast::Attribute { id: attr::mk_attr_id(), style: attr.style, - value: mi.clone(), + path: ast::Path::from_ident(mi.span, ast::Ident::with_empty_ctxt(mi.name)), + tokens: mi.node.tokens(mi.span), is_sugared_doc: false, span: mi.span, }) @@ -132,8 +133,9 @@ impl<'a> StripUnconfigured<'a> { return false; } - let mis = match attr.value.node { - ast::MetaItemKind::List(ref mis) if is_cfg(&attr) => mis, + let mis = attr.meta_item_list(); + let mis = match mis { + Some(ref mis) if is_cfg(&attr) => mis, _ => return true }; diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 77cc7bab031..5b253635f25 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -18,7 +18,7 @@ use syntax_pos::Span; pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec<(Symbol, Span)> { let mut result = Vec::new(); attrs.retain(|attr| { - if attr.name() != "derive" { + if attr.path != "derive" { return true; } @@ -27,7 +27,7 @@ pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec return false; } - let traits = attr.meta_item_list().unwrap_or(&[]).to_owned(); + let traits = attr.meta_item_list().unwrap_or_else(Vec::new); if traits.is_empty() { cx.span_warn(attr.span, "empty trait list in `derive`"); return false; diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 10168f010a0..c1095d34456 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -272,7 +272,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.collect_invocations(expansion, &[]) } else if let InvocationKind::Attr { attr: None, traits, item } = invoc.kind { let item = item - .map_attrs(|mut attrs| { attrs.retain(|a| a.name() != "derive"); attrs }); + .map_attrs(|mut attrs| { attrs.retain(|a| a.path != "derive"); attrs }); let item_with_markers = add_derived_markers(&mut self.cx, &traits, item.clone()); let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new); @@ -380,7 +380,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; attr::mark_used(&attr); - let name = attr.name(); + let name = attr.path.segments[0].identifier.name; self.cx.bt_push(ExpnInfo { call_site: attr.span, callee: NameAndSpan { @@ -392,25 +392,25 @@ impl<'a, 'b> MacroExpander<'a, 'b> { match *ext { MultiModifier(ref mac) => { - let item = mac.expand(self.cx, attr.span, &attr.value, item); + let meta = panictry!(attr.parse_meta(&self.cx.parse_sess)); + let item = mac.expand(self.cx, attr.span, &meta, item); kind.expect_from_annotatables(item) } MultiDecorator(ref mac) => { let mut items = Vec::new(); - mac.expand(self.cx, attr.span, &attr.value, &item, - &mut |item| items.push(item)); + let meta = panictry!(attr.parse_meta(&self.cx.parse_sess)); + mac.expand(self.cx, attr.span, &meta, &item, &mut |item| items.push(item)); items.push(item); kind.expect_from_annotatables(items) } SyntaxExtension::AttrProcMacro(ref mac) => { - let attr_toks = stream_for_attr_args(&attr, &self.cx.parse_sess); let item_toks = stream_for_item(&item, &self.cx.parse_sess); let span = Span { expn_id: self.cx.codemap().record_expansion(ExpnInfo { call_site: attr.span, callee: NameAndSpan { - format: MacroAttribute(name), + format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))), span: None, allow_internal_unstable: false, }, @@ -418,7 +418,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ..attr.span }; - let tok_result = mac.expand(self.cx, attr.span, attr_toks, item_toks); + let tok_result = mac.expand(self.cx, attr.span, attr.tokens.clone(), item_toks); self.parse_expansion(tok_result, kind, name, span) } SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => { @@ -784,32 +784,6 @@ fn stream_for_item(item: &Annotatable, parse_sess: &ParseSess) -> TokenStream { string_to_stream(text, parse_sess) } -fn stream_for_attr_args(attr: &ast::Attribute, parse_sess: &ParseSess) -> TokenStream { - use ast::MetaItemKind::*; - use print::pp::Breaks; - use print::pprust::PrintState; - - let token_string = match attr.value.node { - // For `#[foo]`, an empty token - Word => return TokenStream::empty(), - // For `#[foo(bar, baz)]`, returns `(bar, baz)` - List(ref items) => pprust::to_string(|s| { - s.popen()?; - s.commasep(Breaks::Consistent, - &items[..], - |s, i| s.print_meta_list_item(&i))?; - s.pclose() - }), - // For `#[foo = "bar"]`, returns `= "bar"` - NameValue(ref lit) => pprust::to_string(|s| { - s.word_space("=")?; - s.print_literal(lit) - }), - }; - - string_to_stream(token_string, parse_sess) -} - fn string_to_stream(text: String, parse_sess: &ParseSess) -> TokenStream { let filename = String::from(""); filemap_to_stream(parse_sess, parse_sess.codemap().new_filemap(filename, None, text)) diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 69ff726e719..10b7249743b 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -220,16 +220,24 @@ pub mod rt { } impl ToTokens for ast::Attribute { - fn to_tokens(&self, cx: &ExtCtxt) -> Vec { + fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { let mut r = vec![]; // FIXME: The spans could be better r.push(TokenTree::Token(self.span, token::Pound)); if self.style == ast::AttrStyle::Inner { r.push(TokenTree::Token(self.span, token::Not)); } + let mut inner = Vec::new(); + for (i, segment) in self.path.segments.iter().enumerate() { + if i > 0 { + inner.push(TokenTree::Token(self.span, token::Colon).into()); + } + inner.push(TokenTree::Token(self.span, token::Ident(segment.identifier)).into()); + } + inner.push(self.tokens.clone()); + r.push(TokenTree::Delimited(self.span, tokenstream::Delimited { - delim: token::Bracket, - tts: self.value.to_tokens(cx).into_iter().collect::().into(), + delim: token::Bracket, tts: TokenStream::concat(inner).into() })); r } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e7bf16eae9e..2c3ad98a6be 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -859,35 +859,34 @@ macro_rules! gate_feature { impl<'a> Context<'a> { fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) { debug!("check_attribute(attr = {:?})", attr); - let name = &*attr.name().as_str(); + let name = unwrap_or!(attr.name(), return); + for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES { - if n == name { + if name == n { if let &Gated(_, ref name, ref desc, ref has_feature) = gateage { gate_feature_fn!(self, has_feature, attr.span, name, desc); } - debug!("check_attribute: {:?} is builtin, {:?}, {:?}", name, ty, gateage); + debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage); return; } } for &(ref n, ref ty) in self.plugin_attributes { - if n == name { + if attr.path == &**n { // Plugins can't gate attributes, so we don't check for it // unlike the code above; we only use this loop to // short-circuit to avoid the checks below - debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty); + debug!("check_attribute: {:?} is registered by a plugin, {:?}", attr.path, ty); return; } } - if name.starts_with("rustc_") { + if name.as_str().starts_with("rustc_") { gate_feature!(self, rustc_attrs, attr.span, "unless otherwise specified, attributes \ with the prefix `rustc_` \ are reserved for internal compiler diagnostics"); - } else if name.starts_with("derive_") { + } else if name.as_str().starts_with("derive_") { gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE); - } else if attr::is_known(attr) { - debug!("check_attribute: {:?} is known", name); - } else { + } else if !attr::is_known(attr) { // Only run the custom attribute lint during regular // feature gate checking. Macro gating runs // before the plugin attributes are registered @@ -898,7 +897,7 @@ impl<'a> Context<'a> { unknown to the compiler and \ may have meaning \ added to it in the future", - name)); + attr.path)); } } } @@ -1097,7 +1096,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { self.context.check_attribute(attr, false); } - if contains_novel_literal(&attr.value) { + let meta = panictry!(attr.parse_meta(&self.context.parse_sess)); + if contains_novel_literal(&meta) { gate_feature_post!(&self, attr_literals, attr.span, "non-string literals in attributes, or string \ literals in top-level positions, are experimental"); @@ -1160,8 +1160,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { `#[repr(simd)]` instead"); } for attr in &i.attrs { - if attr.name() == "repr" { - for item in attr.meta_item_list().unwrap_or(&[]) { + if attr.path == "repr" { + for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.check_name("simd") { gate_feature_post!(&self, repr_simd, i.span, "SIMD types are experimental \ diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index fb4eb19be2b..903dac1f379 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -488,7 +488,8 @@ pub fn noop_fold_attribute(attr: Attribute, fld: &mut T) -> Option(nt: token::Nonterminal, fld: &mut T) token::NtExpr(expr) => token::NtExpr(fld.fold_expr(expr)), token::NtTy(ty) => token::NtTy(fld.fold_ty(ty)), token::NtIdent(id) => token::NtIdent(Spanned::{node: fld.fold_ident(id.node), ..id}), - token::NtMeta(meta_item) => token::NtMeta(fld.fold_meta_item(meta_item)), + token::NtMeta(meta) => token::NtMeta(fld.fold_meta_item(meta)), token::NtPath(path) => token::NtPath(fld.fold_path(path)), token::NtTT(tt) => token::NtTT(fld.fold_tt(tt)), token::NtArm(arm) => token::NtArm(fld.fold_arm(arm)), @@ -1369,7 +1370,7 @@ mod tests { matches_codepattern, "matches_codepattern", pprust::to_string(|s| fake_print_crate(s, &folded_crate)), - "#[a]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string()); + "#[zz]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string()); } // even inside macro defs.... diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 39a9aff48bf..4c9a5d512af 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -65,6 +65,16 @@ macro_rules! panictry { }) } +#[macro_export] +macro_rules! unwrap_or { + ($opt:expr, $default:expr) => { + match $opt { + Some(x) => x, + None => $default, + } + } +} + #[macro_use] pub mod diagnostics { #[macro_use] diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index ded676da3c6..272cff7ad34 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -143,7 +143,8 @@ impl<'a> Parser<'a> { Ok(ast::Attribute { id: attr::mk_attr_id(), style: style, - value: value, + path: ast::Path::from_ident(value.span, ast::Ident::with_empty_ctxt(value.name)), + tokens: value.node.tokens(value.span), is_sugared_doc: false, span: span, }) @@ -221,15 +222,20 @@ impl<'a> Parser<'a> { let lo = self.span.lo; let ident = self.parse_ident()?; - let node = if self.eat(&token::Eq) { + let node = self.parse_meta_item_kind()?; + let hi = self.prev_span.hi; + Ok(ast::MetaItem { name: ident.name, node: node, span: mk_sp(lo, hi) }) + } + + pub fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> { + Ok(if self.eat(&token::Eq) { ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?) } else if self.token == token::OpenDelim(token::Paren) { ast::MetaItemKind::List(self.parse_meta_seq()?) } else { + self.eat(&token::OpenDelim(token::Paren)); ast::MetaItemKind::Word - }; - let hi = self.prev_span.hi; - Ok(ast::MetaItem { name: ident.name, node: node, span: mk_sp(lo, hi) }) + }) } /// matches meta_item_inner : (meta_item | UNSUFFIXED_LIT) ; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index c00d2952b3b..2bdd3938d6b 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -374,38 +374,80 @@ fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { s[1..].chars().all(|c| '0' <= c && c <= '9') } -fn filtered_float_lit(data: Symbol, suffix: Option, sd: &Handler, sp: Span) - -> ast::LitKind { +macro_rules! err { + ($opt_diag:expr, |$span:ident, $diag:ident| $($body:tt)*) => { + match $opt_diag { + Some(($span, $diag)) => { $($body)* } + None => return None, + } + } +} + +pub fn lit_token(lit: token::Lit, suf: Option, diag: Option<(Span, &Handler)>) + -> (bool /* suffix illegal? */, Option) { + use ast::LitKind; + + match lit { + token::Byte(i) => (true, Some(LitKind::Byte(byte_lit(&i.as_str()).0))), + token::Char(i) => (true, Some(LitKind::Char(char_lit(&i.as_str()).0))), + + // There are some valid suffixes for integer and float literals, + // so all the handling is done internally. + token::Integer(s) => (false, integer_lit(&s.as_str(), suf, diag)), + token::Float(s) => (false, float_lit(&s.as_str(), suf, diag)), + + token::Str_(s) => { + let s = Symbol::intern(&str_lit(&s.as_str())); + (true, Some(LitKind::Str(s, ast::StrStyle::Cooked))) + } + token::StrRaw(s, n) => { + let s = Symbol::intern(&raw_str_lit(&s.as_str())); + (true, Some(LitKind::Str(s, ast::StrStyle::Raw(n)))) + } + token::ByteStr(i) => { + (true, Some(LitKind::ByteStr(byte_str_lit(&i.as_str())))) + } + token::ByteStrRaw(i, _) => { + (true, Some(LitKind::ByteStr(Rc::new(i.to_string().into_bytes())))) + } + } +} + +fn filtered_float_lit(data: Symbol, suffix: Option, diag: Option<(Span, &Handler)>) + -> Option { debug!("filtered_float_lit: {}, {:?}", data, suffix); let suffix = match suffix { Some(suffix) => suffix, - None => return ast::LitKind::FloatUnsuffixed(data), + None => return Some(ast::LitKind::FloatUnsuffixed(data)), }; - match &*suffix.as_str() { + Some(match &*suffix.as_str() { "f32" => ast::LitKind::Float(data, ast::FloatTy::F32), "f64" => ast::LitKind::Float(data, ast::FloatTy::F64), suf => { - if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) { - // if it looks like a width, lets try to be helpful. - sd.struct_span_err(sp, &format!("invalid width `{}` for float literal", &suf[1..])) - .help("valid widths are 32 and 64") - .emit(); - } else { - sd.struct_span_err(sp, &format!("invalid suffix `{}` for float literal", suf)) - .help("valid suffixes are `f32` and `f64`") - .emit(); - } + err!(diag, |span, diag| { + if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) { + // if it looks like a width, lets try to be helpful. + let msg = format!("invalid width `{}` for float literal", &suf[1..]); + diag.struct_span_err(span, &msg).help("valid widths are 32 and 64").emit() + } else { + let msg = format!("invalid suffix `{}` for float literal", suf); + diag.struct_span_err(span, &msg) + .help("valid suffixes are `f32` and `f64`") + .emit(); + } + }); ast::LitKind::FloatUnsuffixed(data) } - } + }) } -pub fn float_lit(s: &str, suffix: Option, sd: &Handler, sp: Span) -> ast::LitKind { +pub fn float_lit(s: &str, suffix: Option, diag: Option<(Span, &Handler)>) + -> Option { debug!("float_lit: {:?}, {:?}", s, suffix); // FIXME #2252: bounds checking float literals is deferred until trans let s = s.chars().filter(|&c| c != '_').collect::(); - filtered_float_lit(Symbol::intern(&s), suffix, sd, sp) + filtered_float_lit(Symbol::intern(&s), suffix, diag) } /// Parse a string representing a byte literal into its final form. Similar to `char_lit` @@ -500,7 +542,8 @@ pub fn byte_str_lit(lit: &str) -> Rc> { Rc::new(res) } -pub fn integer_lit(s: &str, suffix: Option, sd: &Handler, sp: Span) -> ast::LitKind { +pub fn integer_lit(s: &str, suffix: Option, diag: Option<(Span, &Handler)>) + -> Option { // s can only be ascii, byte indexing is fine let s2 = s.chars().filter(|&c| c != '_').collect::(); @@ -524,13 +567,16 @@ pub fn integer_lit(s: &str, suffix: Option, sd: &Handler, sp: Span) -> a // 1f64 and 2f32 etc. are valid float literals. if let Some(suf) = suffix { if looks_like_width_suffix(&['f'], &suf.as_str()) { - match base { - 16 => sd.span_err(sp, "hexadecimal float literal is not supported"), - 8 => sd.span_err(sp, "octal float literal is not supported"), - 2 => sd.span_err(sp, "binary float literal is not supported"), - _ => () + let err = match base { + 16 => Some("hexadecimal float literal is not supported"), + 8 => Some("octal float literal is not supported"), + 2 => Some("binary float literal is not supported"), + _ => None, + }; + if let Some(err) = err { + err!(diag, |span, diag| diag.span_err(span, err)); } - return filtered_float_lit(Symbol::intern(&s), Some(suf), sd, sp) + return filtered_float_lit(Symbol::intern(&s), Some(suf), diag) } } @@ -539,7 +585,9 @@ pub fn integer_lit(s: &str, suffix: Option, sd: &Handler, sp: Span) -> a } if let Some(suf) = suffix { - if suf.as_str().is_empty() { sd.span_bug(sp, "found empty literal suffix in Some")} + if suf.as_str().is_empty() { + err!(diag, |span, diag| diag.span_bug(span, "found empty literal suffix in Some")); + } ty = match &*suf.as_str() { "isize" => ast::LitIntType::Signed(ast::IntTy::Is), "i8" => ast::LitIntType::Signed(ast::IntTy::I8), @@ -556,17 +604,20 @@ pub fn integer_lit(s: &str, suffix: Option, sd: &Handler, sp: Span) -> a suf => { // i and u look like widths, so lets // give an error message along those lines - if looks_like_width_suffix(&['i', 'u'], suf) { - sd.struct_span_err(sp, &format!("invalid width `{}` for integer literal", - &suf[1..])) - .help("valid widths are 8, 16, 32, 64 and 128") - .emit(); - } else { - sd.struct_span_err(sp, &format!("invalid suffix `{}` for numeric literal", suf)) - .help("the suffix must be one of the integral types \ - (`u32`, `isize`, etc)") - .emit(); - } + err!(diag, |span, diag| { + if looks_like_width_suffix(&['i', 'u'], suf) { + let msg = format!("invalid width `{}` for integer literal", &suf[1..]); + diag.struct_span_err(span, &msg) + .help("valid widths are 8, 16, 32, 64 and 128") + .emit(); + } else { + let msg = format!("invalid suffix `{}` for numeric literal", suf); + diag.struct_span_err(span, &msg) + .help("the suffix must be one of the integral types \ + (`u32`, `isize`, etc)") + .emit(); + } + }); ty } @@ -576,7 +627,7 @@ pub fn integer_lit(s: &str, suffix: Option, sd: &Handler, sp: Span) -> a debug!("integer_lit: the type is {:?}, base {:?}, the new string is {:?}, the original \ string was {:?}, the original suffix was {:?}", ty, base, s, orig, suffix); - match u128::from_str_radix(s, base) { + Some(match u128::from_str_radix(s, base) { Ok(r) => ast::LitKind::Int(r, ty), Err(_) => { // small bases are lexed as if they were base 10, e.g, the string @@ -588,11 +639,11 @@ pub fn integer_lit(s: &str, suffix: Option, sd: &Handler, sp: Span) -> a s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base)); if !already_errored { - sd.span_err(sp, "int literal is too large"); + err!(diag, |span, diag| diag.span_err(span, "int literal is too large")); } ast::LitKind::Int(0, ty) } - } + }) } #[cfg(test)] @@ -957,7 +1008,7 @@ mod tests { let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name.clone(), source, &sess) .unwrap().unwrap(); - let docs = item.attrs.iter().filter(|a| a.name() == "doc") + let docs = item.attrs.iter().filter(|a| a.path == "doc") .map(|a| a.value_str().unwrap().to_string()).collect::>(); let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()]; assert_eq!(&docs[..], b); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9872afd27b7..ed512b89987 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -60,7 +60,6 @@ use util::ThinVec; use std::collections::HashSet; use std::{cmp, mem, slice}; use std::path::{Path, PathBuf}; -use std::rc::Rc; bitflags! { flags Restrictions: u8 { @@ -1643,44 +1642,15 @@ impl<'a> Parser<'a> { _ => { return self.unexpected_last(&self.token); } }, token::Literal(lit, suf) => { - let (suffix_illegal, out) = match lit { - token::Byte(i) => (true, LitKind::Byte(parse::byte_lit(&i.as_str()).0)), - token::Char(i) => (true, LitKind::Char(parse::char_lit(&i.as_str()).0)), - - // there are some valid suffixes for integer and - // float literals, so all the handling is done - // internally. - token::Integer(s) => { - let diag = &self.sess.span_diagnostic; - (false, parse::integer_lit(&s.as_str(), suf, diag, self.span)) - } - token::Float(s) => { - let diag = &self.sess.span_diagnostic; - (false, parse::float_lit(&s.as_str(), suf, diag, self.span)) - } - - token::Str_(s) => { - let s = Symbol::intern(&parse::str_lit(&s.as_str())); - (true, LitKind::Str(s, ast::StrStyle::Cooked)) - } - token::StrRaw(s, n) => { - let s = Symbol::intern(&parse::raw_str_lit(&s.as_str())); - (true, LitKind::Str(s, ast::StrStyle::Raw(n))) - } - token::ByteStr(i) => { - (true, LitKind::ByteStr(parse::byte_str_lit(&i.as_str()))) - } - token::ByteStrRaw(i, _) => { - (true, LitKind::ByteStr(Rc::new(i.to_string().into_bytes()))) - } - }; + let diag = Some((self.span, &self.sess.span_diagnostic)); + let (suffix_illegal, result) = parse::lit_token(lit, suf, diag); if suffix_illegal { let sp = self.span; self.expect_no_suffix(sp, &format!("{} literal", lit.short_name()), suf) } - out + result.unwrap() } _ => { return self.unexpected_last(&self.token); } }; @@ -5135,11 +5105,9 @@ impl<'a> Parser<'a> { let attr = ast::Attribute { id: attr::mk_attr_id(), style: ast::AttrStyle::Outer, - value: ast::MetaItem { - name: Symbol::intern("warn_directory_ownership"), - node: ast::MetaItemKind::Word, - span: syntax_pos::DUMMY_SP, - }, + path: ast::Path::from_ident(syntax_pos::DUMMY_SP, + Ident::from_str("warn_directory_ownership")), + tokens: TokenStream::empty(), is_sugared_doc: false, span: syntax_pos::DUMMY_SP, }; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 5b65aac92b8..38377004572 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -17,7 +17,7 @@ pub use self::Token::*; use ast::{self}; use ptr::P; use symbol::keywords; -use tokenstream; +use tokenstream::TokenTree; use std::fmt; use std::rc::Rc; @@ -348,7 +348,7 @@ pub enum Nonterminal { /// Stuff inside brackets for attributes NtMeta(ast::MetaItem), NtPath(ast::Path), - NtTT(tokenstream::TokenTree), + NtTT(TokenTree), // These are not exposed to macros, but are used by quasiquote. NtArm(ast::Arm), NtImplItem(ast::ImplItem), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 3efadbd00d1..d8af95d8d30 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -28,7 +28,7 @@ use ptr::P; use std_inject; use symbol::{Symbol, keywords}; use syntax_pos::DUMMY_SP; -use tokenstream::{self, TokenTree}; +use tokenstream::{self, TokenStream, TokenTree}; use std::ascii; use std::io::{self, Write, Read}; @@ -329,6 +329,10 @@ pub fn tts_to_string(tts: &[tokenstream::TokenTree]) -> String { to_string(|s| s.print_tts(tts.iter().cloned().collect())) } +pub fn tokens_to_string(tokens: TokenStream) -> String { + to_string(|s| s.print_tts(tokens)) +} + pub fn stmt_to_string(stmt: &ast::Stmt) -> String { to_string(|s| s.print_stmt(stmt)) } @@ -750,7 +754,21 @@ pub trait PrintState<'a> { ast::AttrStyle::Inner => word(self.writer(), "#![")?, ast::AttrStyle::Outer => word(self.writer(), "#[")?, } - self.print_meta_item(&attr.meta())?; + if let Some(mi) = attr.meta() { + self.print_meta_item(&mi)? + } else { + for (i, segment) in attr.path.segments.iter().enumerate() { + if i > 0 { + word(self.writer(), "::")? + } + if segment.identifier.name != keywords::CrateRoot.name() && + segment.identifier.name != "$crate" { + word(self.writer(), &segment.identifier.name.as_str())?; + } + } + space(self.writer())?; + self.print_tts(attr.tokens.clone())?; + } word(self.writer(), "]") } } @@ -789,6 +807,45 @@ pub trait PrintState<'a> { self.end() } + /// This doesn't deserve to be called "pretty" printing, but it should be + /// meaning-preserving. A quick hack that might help would be to look at the + /// spans embedded in the TTs to decide where to put spaces and newlines. + /// But it'd be better to parse these according to the grammar of the + /// appropriate macro, transcribe back into the grammar we just parsed from, + /// and then pretty-print the resulting AST nodes (so, e.g., we print + /// expression arguments as expressions). It can be done! I think. + fn print_tt(&mut self, tt: tokenstream::TokenTree) -> io::Result<()> { + match tt { + TokenTree::Token(_, ref tk) => { + word(self.writer(), &token_to_string(tk))?; + match *tk { + parse::token::DocComment(..) => { + hardbreak(self.writer()) + } + _ => Ok(()) + } + } + TokenTree::Delimited(_, ref delimed) => { + word(self.writer(), &token_to_string(&delimed.open_token()))?; + space(self.writer())?; + self.print_tts(delimed.stream())?; + space(self.writer())?; + word(self.writer(), &token_to_string(&delimed.close_token())) + }, + } + } + + fn print_tts(&mut self, tts: tokenstream::TokenStream) -> io::Result<()> { + self.ibox(0)?; + for (i, tt) in tts.into_trees().enumerate() { + if i != 0 { + space(self.writer())?; + } + self.print_tt(tt)?; + } + self.end() + } + fn space_if_not_bol(&mut self) -> io::Result<()> { if !self.is_bol() { space(self.writer())?; } Ok(()) @@ -1458,45 +1515,6 @@ impl<'a> State<'a> { } } - /// This doesn't deserve to be called "pretty" printing, but it should be - /// meaning-preserving. A quick hack that might help would be to look at the - /// spans embedded in the TTs to decide where to put spaces and newlines. - /// But it'd be better to parse these according to the grammar of the - /// appropriate macro, transcribe back into the grammar we just parsed from, - /// and then pretty-print the resulting AST nodes (so, e.g., we print - /// expression arguments as expressions). It can be done! I think. - pub fn print_tt(&mut self, tt: tokenstream::TokenTree) -> io::Result<()> { - match tt { - TokenTree::Token(_, ref tk) => { - word(&mut self.s, &token_to_string(tk))?; - match *tk { - parse::token::DocComment(..) => { - hardbreak(&mut self.s) - } - _ => Ok(()) - } - } - TokenTree::Delimited(_, ref delimed) => { - word(&mut self.s, &token_to_string(&delimed.open_token()))?; - space(&mut self.s)?; - self.print_tts(delimed.stream())?; - space(&mut self.s)?; - word(&mut self.s, &token_to_string(&delimed.close_token())) - }, - } - } - - pub fn print_tts(&mut self, tts: tokenstream::TokenStream) -> io::Result<()> { - self.ibox(0)?; - for (i, tt) in tts.into_trees().enumerate() { - if i != 0 { - space(&mut self.s)?; - } - self.print_tt(tt)?; - } - self.end() - } - pub fn print_variant(&mut self, v: &ast::Variant) -> io::Result<()> { self.head("")?; let generics = ast::Generics::default(); diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 4a2dfaf6124..94954e2c429 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -15,6 +15,7 @@ use syntax_pos::{DUMMY_SP, Span}; use codemap::{self, ExpnInfo, NameAndSpan, MacroAttribute}; use parse::ParseSess; use ptr::P; +use tokenstream::TokenStream; /// Craft a span that will be ignored by the stability lint's /// call to codemap's is_internal check. @@ -70,11 +71,8 @@ pub fn maybe_inject_crates_ref(sess: &ParseSess, krate.module.items.insert(0, P(ast::Item { attrs: vec![ast::Attribute { style: ast::AttrStyle::Outer, - value: ast::MetaItem { - name: Symbol::intern("prelude_import"), - node: ast::MetaItemKind::Word, - span: span, - }, + path: ast::Path::from_ident(span, ast::Ident::from_str("prelude_import")), + tokens: TokenStream::empty(), id: attr::mk_attr_id(), is_sugared_doc: false, span: span, diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 2da442a1a53..35e4d9eb68a 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -360,7 +360,7 @@ impl PartialEq for ThinTokenStream { impl fmt::Display for TokenStream { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(&pprust::tts_to_string(&self.trees().collect::>())) + f.write_str(&pprust::tokens_to_string(self.clone())) } } diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs index a7e2d82bb97..b01ef65e5fe 100644 --- a/src/libsyntax_ext/deriving/custom.rs +++ b/src/libsyntax_ext/deriving/custom.rs @@ -23,9 +23,11 @@ struct MarkAttrs<'a>(&'a [ast::Name]); impl<'a> Visitor<'a> for MarkAttrs<'a> { fn visit_attribute(&mut self, attr: &Attribute) { - if self.0.contains(&attr.name()) { - mark_used(attr); - mark_known(attr); + if let Some(name) = attr.name() { + if self.0.contains(&name) { + mark_used(attr); + mark_known(attr); + } } } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index fe492bd7fc8..48e7ff0d243 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -439,7 +439,7 @@ impl<'a> TraitDef<'a> { attrs.extend(item.attrs .iter() .filter(|a| { - match &*a.name().as_str() { + a.name().is_some() && match &*a.name().unwrap().as_str() { "allow" | "warn" | "deny" | "forbid" | "stable" | "unstable" => true, _ => false, } diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index 5adaf470f23..2d815b3f1bb 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -248,7 +248,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { fn visit_item(&mut self, item: &'a ast::Item) { if let ast::ItemKind::MacroDef(..) = item.node { if self.is_proc_macro_crate && - item.attrs.iter().any(|attr| attr.name() == "macro_export") { + item.attrs.iter().any(|attr| attr.path == "macro_export") { let msg = "cannot export macro_rules! macros from a `proc-macro` crate type currently"; self.handler.span_err(item.span, msg); @@ -270,12 +270,12 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { for attr in &item.attrs { if is_proc_macro_attr(&attr) { if let Some(prev_attr) = found_attr { - let msg = if attr.name() == prev_attr.name() { + let msg = if attr.path == prev_attr.path { format!("Only one `#[{}]` attribute is allowed on any given function", - attr.name()) + attr.path) } else { format!("`#[{}]` and `#[{}]` attributes cannot both be applied \ - to the same function", attr.name(), prev_attr.name()) + to the same function", attr.path, prev_attr.path) }; self.handler.struct_span_err(attr.span(), &msg) @@ -299,7 +299,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { if !is_fn { let msg = format!("the `#[{}]` attribute may only be used on bare functions", - attr.name()); + attr.path); self.handler.span_err(attr.span(), &msg); return; @@ -311,7 +311,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { if !self.is_proc_macro_crate { let msg = format!("the `#[{}]` attribute is only usable with crates of the \ - `proc-macro` crate type", attr.name()); + `proc-macro` crate type", attr.path); self.handler.span_err(attr.span(), &msg); return; -- cgit 1.4.1-3-g733a5 From 839c2860ccb7cd3d381abf2838dfba566f52618e Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 8 Mar 2017 23:13:35 +0000 Subject: Liberalize attributes. --- src/librustc_resolve/lib.rs | 2 + src/librustc_resolve/macros.rs | 54 +++++++++----- src/libsyntax/attr.rs | 46 +++++++++++- src/libsyntax/config.rs | 72 +++++++++---------- src/libsyntax/ext/derive.rs | 45 ++++++------ src/libsyntax/ext/expand.rs | 94 +++++++++++++------------ src/libsyntax/ext/tt/macro_rules.rs | 3 +- src/libsyntax/feature_gate.rs | 4 ++ src/libsyntax/parse/attr.rs | 32 +++++++-- src/libsyntax/parse/parser.rs | 11 +++ src/test/compile-fail/macro-attribute.rs | 12 ++++ src/test/compile-fail/malformed-derive-entry.rs | 4 +- src/test/compile-fail/suffixed-literal-meta.rs | 25 +++++++ src/test/parse-fail/attr-bad-meta.rs | 6 +- src/test/parse-fail/macro-attribute.rs | 14 ---- src/test/parse-fail/suffixed-literal-meta.rs | 25 ------- src/test/ui/span/E0536.stderr | 2 +- src/test/ui/span/E0537.stderr | 2 +- 18 files changed, 269 insertions(+), 184 deletions(-) create mode 100644 src/test/compile-fail/macro-attribute.rs create mode 100644 src/test/compile-fail/suffixed-literal-meta.rs delete mode 100644 src/test/parse-fail/macro-attribute.rs delete mode 100644 src/test/parse-fail/suffixed-literal-meta.rs (limited to 'src/libsyntax/parse') diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c3e471650a3..bf7115abd4e 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1165,6 +1165,7 @@ pub struct Resolver<'a> { privacy_errors: Vec>, ambiguity_errors: Vec>, + gated_errors: FxHashSet, disallowed_shadowing: Vec<&'a LegacyBinding<'a>>, arenas: &'a ResolverArenas<'a>, @@ -1355,6 +1356,7 @@ impl<'a> Resolver<'a> { privacy_errors: Vec::new(), ambiguity_errors: Vec::new(), + gated_errors: FxHashSet(), disallowed_shadowing: Vec::new(), arenas: arenas, diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 9e1dcd1bc35..67ce24efb3b 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -28,9 +28,11 @@ use syntax::ext::placeholders::placeholder; use syntax::ext::tt::macro_rules; use syntax::feature_gate::{self, emit_feature_err, GateIssue}; use syntax::fold::{self, Folder}; +use syntax::parse::parser::PathStyle; +use syntax::parse::token::{self, Token}; use syntax::ptr::P; use syntax::symbol::{Symbol, keywords}; -use syntax::tokenstream::TokenStream; +use syntax::tokenstream::{TokenStream, TokenTree, Delimited}; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::{Span, DUMMY_SP}; @@ -200,16 +202,22 @@ impl<'a> base::Resolver for Resolver<'a> { let name = unwrap_or!(attrs[i].name(), continue); if name == "derive" { - let mut traits = match attrs[i].meta_item_list() { - Some(traits) => traits, - _ => continue, + let result = attrs[i].parse_list(&self.session.parse_sess, + |parser| parser.parse_path(PathStyle::Mod)); + let mut traits = match result { + Ok(traits) => traits, + Err(mut e) => { + e.cancel(); + continue + } }; for j in 0..traits.len() { - let legacy_name = Symbol::intern(&match traits[j].word() { - Some(..) => format!("derive_{}", traits[j].name().unwrap()), - None => continue, - }); + if traits[j].segments.len() > 1 { + continue + } + let trait_name = traits[j].segments[0].identifier.name; + let legacy_name = Symbol::intern(&format!("derive_{}", trait_name)); if !self.builtin_macros.contains_key(&legacy_name) { continue } @@ -218,7 +226,23 @@ impl<'a> base::Resolver for Resolver<'a> { if traits.is_empty() { attrs.remove(i); } else { - attrs[i].tokens = ast::MetaItemKind::List(traits).tokens(attrs[i].span); + let mut tokens = Vec::new(); + for (i, path) in traits.iter().enumerate() { + if i > 0 { + tokens.push(TokenTree::Token(attrs[i].span, Token::Comma).into()); + } + for (j, segment) in path.segments.iter().enumerate() { + if j > 0 { + tokens.push(TokenTree::Token(path.span, Token::ModSep).into()); + } + let tok = Token::Ident(segment.identifier); + tokens.push(TokenTree::Token(path.span, tok).into()); + } + } + attrs[i].tokens = TokenTree::Delimited(attrs[i].span, Delimited { + delim: token::Paren, + tts: TokenStream::concat(tokens).into(), + }).into(); } return Some(ast::Attribute { path: ast::Path::from_ident(span, Ident::with_empty_ctxt(legacy_name)), @@ -262,9 +286,8 @@ impl<'a> Resolver<'a> { InvocationKind::Bang { ref mac, .. } => { return self.resolve_macro_to_def(scope, &mac.node.path, MacroKind::Bang, force); } - InvocationKind::Derive { name, span, .. } => { - let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); - return self.resolve_macro_to_def(scope, &path, MacroKind::Derive, force); + InvocationKind::Derive { ref path, .. } => { + return self.resolve_macro_to_def(scope, path, MacroKind::Derive, force); } }; @@ -282,9 +305,8 @@ impl<'a> Resolver<'a> { 1 => path.segments[0].identifier.name, _ => return Err(determinacy), }; - for &(name, span) in traits { - let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); - match self.resolve_macro(scope, &path, MacroKind::Derive, force) { + for path in traits { + match self.resolve_macro(scope, path, MacroKind::Derive, force) { Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs) = *ext { if inert_attrs.contains(&attr_name) { // FIXME(jseyfried) Avoid `mem::replace` here. @@ -327,7 +349,7 @@ impl<'a> Resolver<'a> { self.current_module = invocation.module.get(); if path.len() > 1 { - if !self.use_extern_macros { + if !self.use_extern_macros && self.gated_errors.insert(span) { let msg = "non-ident macro paths are experimental"; let feature = "use_extern_macros"; emit_feature_err(&self.session.parse_sess, feature, span, GateIssue::Language, msg); diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 68f1f690a62..2f1efd6ad00 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -17,7 +17,7 @@ pub use self::IntType::*; use ast; use ast::{AttrId, Attribute, Name, Ident}; use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; -use ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind}; +use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind}; use codemap::{Spanned, spanned, dummy_spanned, mk_sp}; use syntax_pos::{Span, BytePos, DUMMY_SP}; use errors::Handler; @@ -299,6 +299,37 @@ impl Attribute { }) } + pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T> + where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, + { + let mut parser = Parser::new(sess, self.tokens.clone(), None, false); + let result = f(&mut parser)?; + if parser.token != token::Eof { + parser.unexpected()?; + } + Ok(result) + } + + pub fn parse_list<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, Vec> + where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, + { + if self.tokens.is_empty() { + return Ok(Vec::new()); + } + self.parse(sess, |parser| { + parser.expect(&token::OpenDelim(token::Paren))?; + let mut list = Vec::new(); + while !parser.eat(&token::CloseDelim(token::Paren)) { + list.push(f(parser)?); + if !parser.eat(&token::Comma) { + parser.expect(&token::CloseDelim(token::Paren))?; + break + } + } + Ok(list) + }) + } + pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> { if self.path.segments.len() > 1 { sess.span_diagnostic.span_err(self.path.span, "expected ident, found path"); @@ -306,7 +337,7 @@ impl Attribute { Ok(MetaItem { name: self.path.segments.last().unwrap().identifier.name, - node: Parser::new(sess, self.tokens.clone(), None, false).parse_meta_item_kind()?, + node: self.parse(sess, |parser| parser.parse_meta_item_kind())?, span: self.span, }) } @@ -985,6 +1016,10 @@ impl MetaItem { { let (mut span, name) = match tokens.next() { Some(TokenTree::Token(span, Token::Ident(ident))) => (span, ident.name), + Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => return match **nt { + token::Nonterminal::NtMeta(ref meta) => Some(meta.clone()), + _ => None, + }, _ => return None, }; let node = match MetaItemKind::from_tokens(tokens) { @@ -1151,6 +1186,13 @@ impl LitKind { match token { Token::Ident(ident) if ident.name == "true" => Some(LitKind::Bool(true)), Token::Ident(ident) if ident.name == "false" => Some(LitKind::Bool(false)), + Token::Interpolated(ref nt) => match **nt { + token::NtExpr(ref v) => match v.node { + ExprKind::Lit(ref lit) => Some(lit.node.clone()), + _ => None, + }, + _ => None, + }, Token::Literal(lit, suf) => { let (suffix_illegal, result) = parse::lit_token(lit, suf, None); if suffix_illegal && suf.is_some() { diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 2591a576669..ede8a33df65 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -13,9 +13,10 @@ use feature_gate::{feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features use {fold, attr}; use ast; use codemap::Spanned; -use parse::ParseSess; -use ptr::P; +use parse::{token, ParseSess}; +use syntax_pos::Span; +use ptr::P; use util::small_vector::SmallVector; /// A folder that strips out items that do not belong in the current configuration. @@ -84,44 +85,33 @@ impl<'a> StripUnconfigured<'a> { return Some(attr); } - let attr_list = match attr.meta_item_list() { - Some(attr_list) => attr_list, - None => { - let msg = "expected `#[cfg_attr(, )]`"; - self.sess.span_diagnostic.span_err(attr.span, msg); - return None; - } - }; - - let (cfg, mi) = match (attr_list.len(), attr_list.get(0), attr_list.get(1)) { - (2, Some(cfg), Some(mi)) => (cfg, mi), - _ => { - let msg = "expected `#[cfg_attr(, )]`"; - self.sess.span_diagnostic.span_err(attr.span, msg); + let (cfg, path, tokens, span) = match attr.parse(self.sess, |parser| { + parser.expect(&token::OpenDelim(token::Paren))?; + let cfg = parser.parse_meta_item()?; + parser.expect(&token::Comma)?; + let lo = parser.span.lo; + let (path, tokens) = parser.parse_path_and_tokens()?; + parser.expect(&token::CloseDelim(token::Paren))?; + Ok((cfg, path, tokens, Span { lo: lo, ..parser.prev_span })) + }) { + Ok(result) => result, + Err(mut e) => { + e.emit(); return None; } }; - use attr::cfg_matches; - match (cfg.meta_item(), mi.meta_item()) { - (Some(cfg), Some(mi)) => - if cfg_matches(&cfg, self.sess, self.features) { - self.process_cfg_attr(ast::Attribute { - id: attr::mk_attr_id(), - style: attr.style, - path: ast::Path::from_ident(mi.span, ast::Ident::with_empty_ctxt(mi.name)), - tokens: mi.node.tokens(mi.span), - is_sugared_doc: false, - span: mi.span, - }) - } else { - None - }, - _ => { - let msg = "unexpected literal(s) in `#[cfg_attr(, )]`"; - self.sess.span_diagnostic.span_err(attr.span, msg); - None - } + if attr::cfg_matches(&cfg, self.sess, self.features) { + self.process_cfg_attr(ast::Attribute { + id: attr::mk_attr_id(), + style: attr.style, + path: path, + tokens: tokens, + is_sugared_doc: false, + span: span, + }) + } else { + None } } @@ -133,10 +123,12 @@ impl<'a> StripUnconfigured<'a> { return false; } - let mis = attr.meta_item_list(); - let mis = match mis { - Some(ref mis) if is_cfg(&attr) => mis, - _ => return true + let mis = if !is_cfg(&attr) { + return true; + } else if let Some(mis) = attr.meta_item_list() { + mis + } else { + return true; }; if mis.len() != 1 { diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 5b253635f25..1569d9f540b 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -12,36 +12,31 @@ use attr::HasAttrs; use {ast, codemap}; use ext::base::ExtCtxt; use ext::build::AstBuilder; +use parse::parser::PathStyle; use symbol::Symbol; use syntax_pos::Span; -pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec<(Symbol, Span)> { +pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec { let mut result = Vec::new(); attrs.retain(|attr| { if attr.path != "derive" { return true; } - if attr.value_str().is_some() { - cx.span_err(attr.span, "unexpected value in `derive`"); - return false; - } - - let traits = attr.meta_item_list().unwrap_or_else(Vec::new); - if traits.is_empty() { - cx.span_warn(attr.span, "empty trait list in `derive`"); - return false; - } - - for titem in traits { - if titem.word().is_none() { - cx.span_err(titem.span, "malformed `derive` entry"); - return false; + match attr.parse_list(cx.parse_sess, |parser| parser.parse_path(PathStyle::Mod)) { + Ok(ref traits) if traits.is_empty() => { + cx.span_warn(attr.span, "empty trait list in `derive`"); + false + } + Ok(traits) => { + result.extend(traits); + true + } + Err(mut e) => { + e.emit(); + false } - result.push((titem.name().unwrap(), titem.span)); } - - true }); result } @@ -60,21 +55,21 @@ fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span { } } -pub fn add_derived_markers(cx: &mut ExtCtxt, traits: &[(Symbol, Span)], item: T) -> T { +pub fn add_derived_markers(cx: &mut ExtCtxt, traits: &[ast::Path], item: T) -> T { let span = match traits.get(0) { - Some(&(_, span)) => span, + Some(path) => path.span, None => return item, }; item.map_attrs(|mut attrs| { - if traits.iter().any(|&(name, _)| name == "PartialEq") && - traits.iter().any(|&(name, _)| name == "Eq") { + if traits.iter().any(|path| *path == "PartialEq") && + traits.iter().any(|path| *path == "Eq") { let span = allow_unstable(cx, span, "derive(PartialEq, Eq)"); let meta = cx.meta_word(span, Symbol::intern("structural_match")); attrs.push(cx.attribute(span, meta)); } - if traits.iter().any(|&(name, _)| name == "Copy") && - traits.iter().any(|&(name, _)| name == "Clone") { + if traits.iter().any(|path| *path == "Copy") && + traits.iter().any(|path| *path == "Clone") { let span = allow_unstable(cx, span, "derive(Copy, Clone)"); let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker")); attrs.push(cx.attribute(span, meta)); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index c1095d34456..c1816582bc6 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast::{self, Block, Ident, PatKind}; -use ast::{Name, MacStmtStyle, StmtKind, ItemKind}; +use ast::{self, Block, Ident, PatKind, Path}; +use ast::{MacStmtStyle, StmtKind, ItemKind}; use attr::{self, HasAttrs}; use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; use config::{is_test_or_bench, StripUnconfigured}; @@ -27,7 +27,7 @@ use ptr::P; use std_inject; use symbol::Symbol; use symbol::keywords; -use syntax_pos::{self, Span, ExpnId}; +use syntax_pos::{Span, ExpnId, DUMMY_SP}; use tokenstream::TokenStream; use util::small_vector::SmallVector; use visit::Visitor; @@ -165,12 +165,11 @@ pub enum InvocationKind { }, Attr { attr: Option, - traits: Vec<(Symbol, Span)>, + traits: Vec, item: Annotatable, }, Derive { - name: Symbol, - span: Span, + path: Path, item: Annotatable, }, } @@ -180,8 +179,8 @@ impl Invocation { match self.kind { InvocationKind::Bang { span, .. } => span, InvocationKind::Attr { attr: Some(ref attr), .. } => attr.span, - InvocationKind::Attr { attr: None, .. } => syntax_pos::DUMMY_SP, - InvocationKind::Derive { span, .. } => span, + InvocationKind::Attr { attr: None, .. } => DUMMY_SP, + InvocationKind::Derive { ref path, .. } => path.span, } } } @@ -277,12 +276,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { add_derived_markers(&mut self.cx, &traits, item.clone()); let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new); - for &(name, span) in &traits { + for path in &traits { let mark = Mark::fresh(); derives.push(mark); - let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); let item = match self.cx.resolver.resolve_macro( - Mark::root(), &path, MacroKind::Derive, false) { + Mark::root(), path, MacroKind::Derive, false) { Ok(ext) => match *ext { SyntaxExtension::BuiltinDerive(..) => item_with_markers.clone(), _ => item.clone(), @@ -290,7 +288,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { _ => item.clone(), }; invocations.push(Invocation { - kind: InvocationKind::Derive { name: name, span: span, item: item }, + kind: InvocationKind::Derive { path: path.clone(), item: item }, expansion_kind: invoc.expansion_kind, expansion_data: ExpansionData { mark: mark, @@ -380,11 +378,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; attr::mark_used(&attr); - let name = attr.path.segments[0].identifier.name; self.cx.bt_push(ExpnInfo { call_site: attr.span, callee: NameAndSpan { - format: MacroAttribute(name), + format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))), span: Some(attr.span), allow_internal_unstable: false, } @@ -419,14 +416,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; let tok_result = mac.expand(self.cx, attr.span, attr.tokens.clone(), item_toks); - self.parse_expansion(tok_result, kind, name, span) + self.parse_expansion(tok_result, kind, &attr.path, span) } SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => { - self.cx.span_err(attr.span, &format!("`{}` is a derive mode", name)); + self.cx.span_err(attr.span, &format!("`{}` is a derive mode", attr.path)); kind.dummy(attr.span) } _ => { - let msg = &format!("macro `{}` may not be used in attributes", name); + let msg = &format!("macro `{}` may not be used in attributes", attr.path); self.cx.span_err(attr.span, &msg); kind.dummy(attr.span) } @@ -442,7 +439,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; let path = &mac.node.path; - let extname = path.segments.last().unwrap().identifier.name; let ident = ident.unwrap_or(keywords::Invalid.ident()); let marked_tts = noop_fold_tts(mac.node.stream(), &mut Marker { mark: mark, expn_id: None }); @@ -450,7 +446,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { NormalTT(ref expandfun, exp_span, allow_internal_unstable) => { if ident.name != keywords::Invalid.name() { let msg = - format!("macro {}! expects no ident argument, given '{}'", extname, ident); + format!("macro {}! expects no ident argument, given '{}'", path, ident); self.cx.span_err(path.span, &msg); return kind.dummy(span); } @@ -458,7 +454,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.bt_push(ExpnInfo { call_site: span, callee: NameAndSpan { - format: MacroBang(extname), + format: MacroBang(Symbol::intern(&format!("{}", path))), span: exp_span, allow_internal_unstable: allow_internal_unstable, }, @@ -470,14 +466,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { IdentTT(ref expander, tt_span, allow_internal_unstable) => { if ident.name == keywords::Invalid.name() { self.cx.span_err(path.span, - &format!("macro {}! expects an ident argument", extname)); + &format!("macro {}! expects an ident argument", path)); return kind.dummy(span); }; self.cx.bt_push(ExpnInfo { call_site: span, callee: NameAndSpan { - format: MacroBang(extname), + format: MacroBang(Symbol::intern(&format!("{}", path))), span: tt_span, allow_internal_unstable: allow_internal_unstable, } @@ -489,19 +485,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> { MultiDecorator(..) | MultiModifier(..) | SyntaxExtension::AttrProcMacro(..) => { self.cx.span_err(path.span, - &format!("`{}` can only be used in attributes", extname)); + &format!("`{}` can only be used in attributes", path)); return kind.dummy(span); } SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => { - self.cx.span_err(path.span, &format!("`{}` is a derive mode", extname)); + self.cx.span_err(path.span, &format!("`{}` is a derive mode", path)); return kind.dummy(span); } SyntaxExtension::ProcMacro(ref expandfun) => { if ident.name != keywords::Invalid.name() { let msg = - format!("macro {}! expects no ident argument, given '{}'", extname, ident); + format!("macro {}! expects no ident argument, given '{}'", path, ident); self.cx.span_err(path.span, &msg); return kind.dummy(span); } @@ -509,7 +505,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.bt_push(ExpnInfo { call_site: span, callee: NameAndSpan { - format: MacroBang(extname), + format: MacroBang(Symbol::intern(&format!("{}", path))), // FIXME procedural macros do not have proper span info // yet, when they do, we should use it here. span: None, @@ -519,7 +515,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }); let tok_result = expandfun.expand(self.cx, span, marked_tts); - Some(self.parse_expansion(tok_result, kind, extname, span)) + Some(self.parse_expansion(tok_result, kind, path, span)) } }; @@ -541,19 +537,24 @@ impl<'a, 'b> MacroExpander<'a, 'b> { /// Expand a derive invocation. Returns the result of expansion. fn expand_derive_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { let Invocation { expansion_kind: kind, .. } = invoc; - let (name, span, item) = match invoc.kind { - InvocationKind::Derive { name, span, item } => (name, span, item), + let (path, item) = match invoc.kind { + InvocationKind::Derive { path, item } => (path, item), _ => unreachable!(), }; - let mitem = ast::MetaItem { name: name, span: span, node: ast::MetaItemKind::Word }; - let pretty_name = Symbol::intern(&format!("derive({})", name)); + let pretty_name = Symbol::intern(&format!("derive({})", path)); + let span = path.span; + let attr = ast::Attribute { + path: path, tokens: TokenStream::empty(), span: span, + // irrelevant: + id: ast::AttrId(0), style: ast::AttrStyle::Outer, is_sugared_doc: false, + }; self.cx.bt_push(ExpnInfo { call_site: span, callee: NameAndSpan { format: MacroAttribute(pretty_name), - span: Some(span), + span: None, allow_internal_unstable: false, } }); @@ -571,7 +572,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }), ..span }; - return kind.expect_from_annotatables(ext.expand(self.cx, span, &mitem, item)); + let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this + name: keywords::Invalid.name(), + span: DUMMY_SP, + node: ast::MetaItemKind::Word, + }; + return kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item)); } SyntaxExtension::BuiltinDerive(func) => { let span = Span { @@ -586,20 +592,18 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ..span }; let mut items = Vec::new(); - func(self.cx, span, &mitem, &item, &mut |a| { - items.push(a) - }); + func(self.cx, span, &attr.meta().unwrap(), &item, &mut |a| items.push(a)); return kind.expect_from_annotatables(items); } _ => { - let msg = &format!("macro `{}` may not be used for derive attributes", name); + let msg = &format!("macro `{}` may not be used for derive attributes", attr.path); self.cx.span_err(span, &msg); kind.dummy(span) } } } - fn parse_expansion(&mut self, toks: TokenStream, kind: ExpansionKind, name: Name, span: Span) + fn parse_expansion(&mut self, toks: TokenStream, kind: ExpansionKind, path: &Path, span: Span) -> Expansion { let mut parser = self.cx.new_parser_from_tts(&toks.into_trees().collect::>()); let expansion = match parser.parse_expansion(kind, false) { @@ -609,7 +613,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); } }; - parser.ensure_complete_parse(name, kind.name(), span); + parser.ensure_complete_parse(path, kind.name(), span); // FIXME better span info expansion.fold_with(&mut ChangeSpan { span: span }) } @@ -658,14 +662,14 @@ impl<'a> Parser<'a> { }) } - pub fn ensure_complete_parse(&mut self, macro_name: ast::Name, kind_name: &str, span: Span) { + pub fn ensure_complete_parse(&mut self, macro_path: &Path, kind_name: &str, span: Span) { if self.token != token::Eof { let msg = format!("macro expansion ignores token `{}` and any following", self.this_token_to_string()); let mut err = self.diagnostic().struct_span_err(self.span, &msg); let msg = format!("caused by the macro expansion here; the usage \ of `{}!` is likely invalid in {} context", - macro_name, kind_name); + macro_path, kind_name); err.span_note(span, &msg).emit(); } } @@ -708,20 +712,20 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect_attr(&mut self, attr: Option, - traits: Vec<(Symbol, Span)>, + traits: Vec, item: Annotatable, kind: ExpansionKind) -> Expansion { if !traits.is_empty() && (kind == ExpansionKind::TraitItems || kind == ExpansionKind::ImplItems) { - self.cx.span_err(traits[0].1, "`derive` can be only be applied to items"); + self.cx.span_err(traits[0].span, "`derive` can be only be applied to items"); return kind.expect_from_annotatables(::std::iter::once(item)); } self.collect(kind, InvocationKind::Attr { attr: attr, traits: traits, item: item }) } // If `item` is an attr invocation, remove and return the macro attribute. - fn classify_item(&mut self, mut item: T) -> (Option, Vec<(Symbol, Span)>, T) + fn classify_item(&mut self, mut item: T) -> (Option, Vec, T) where T: HasAttrs, { let (mut attr, mut traits) = (None, Vec::new()); @@ -900,7 +904,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { // Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`). // In the non-inline case, `inner` is never the dummy span (c.f. `parse_item_mod`). // Thus, if `inner` is the dummy span, we know the module is inline. - let inline_module = item.span.contains(inner) || inner == syntax_pos::DUMMY_SP; + let inline_module = item.span.contains(inner) || inner == DUMMY_SP; if inline_module { if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, "path") { diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 7aa1230f9ae..021c5398a42 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -51,7 +51,8 @@ impl<'a> ParserAnyMacro<'a> { } // Make sure we don't have any tokens left to parse so we don't silently drop anything. - parser.ensure_complete_parse(macro_ident.name, kind.name(), site_span); + let path = ast::Path::from_ident(site_span, macro_ident); + parser.ensure_complete_parse(&path, kind.name(), site_span); expansion } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 2c3ad98a6be..05e7b0f9aa4 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1096,6 +1096,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { self.context.check_attribute(attr, false); } + if self.context.features.proc_macro && attr::is_known(attr) { + return + } + let meta = panictry!(attr.parse_meta(&self.context.parse_sess)); if contains_novel_literal(&meta) { gate_feature_post!(&self, attr_literals, attr.span, diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 272cff7ad34..53106214fa3 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -14,8 +14,9 @@ use syntax_pos::{mk_sp, Span}; use codemap::spanned; use parse::common::SeqSep; use parse::PResult; -use parse::token; -use parse::parser::{Parser, TokenType}; +use parse::token::{self, Nonterminal}; +use parse::parser::{Parser, TokenType, PathStyle}; +use tokenstream::TokenStream; #[derive(PartialEq, Eq, Debug)] enum InnerAttributeParsePolicy<'a> { @@ -91,7 +92,7 @@ impl<'a> Parser<'a> { debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}", inner_parse_policy, self.token); - let (span, value, mut style) = match self.token { + let (span, path, tokens, mut style) = match self.token { token::Pound => { let lo = self.span.lo; self.bump(); @@ -119,11 +120,11 @@ impl<'a> Parser<'a> { }; self.expect(&token::OpenDelim(token::Bracket))?; - let meta_item = self.parse_meta_item()?; + let (path, tokens) = self.parse_path_and_tokens()?; self.expect(&token::CloseDelim(token::Bracket))?; let hi = self.prev_span.hi; - (mk_sp(lo, hi), meta_item, style) + (mk_sp(lo, hi), path, tokens, style) } _ => { let token_str = self.this_token_to_string(); @@ -143,13 +144,30 @@ impl<'a> Parser<'a> { Ok(ast::Attribute { id: attr::mk_attr_id(), style: style, - path: ast::Path::from_ident(value.span, ast::Ident::with_empty_ctxt(value.name)), - tokens: value.node.tokens(value.span), + path: path, + tokens: tokens, is_sugared_doc: false, span: span, }) } + pub fn parse_path_and_tokens(&mut self) -> PResult<'a, (ast::Path, TokenStream)> { + let meta = match self.token { + token::Interpolated(ref nt) => match **nt { + Nonterminal::NtMeta(ref meta) => Some(meta.clone()), + _ => None, + }, + _ => None, + }; + Ok(if let Some(meta) = meta { + self.bump(); + (ast::Path::from_ident(meta.span, ast::Ident::with_empty_ctxt(meta.name)), + meta.node.tokens(meta.span)) + } else { + (self.parse_path(PathStyle::Mod)?, self.parse_tokens()) + }) + } + /// Parse attributes that appear after the opening of an item. These should /// be preceded by an exclamation mark, but we accept and warn about one /// terminated by a semicolon. diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ed512b89987..308876fed56 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2644,6 +2644,17 @@ impl<'a> Parser<'a> { Ok(tts) } + pub fn parse_tokens(&mut self) -> TokenStream { + let mut result = Vec::new(); + loop { + match self.token { + token::Eof | token::CloseDelim(..) => break, + _ => result.push(self.parse_token_tree().into()), + } + } + TokenStream::concat(result) + } + /// Parse a prefix-unary-operator expr pub fn parse_prefix_expr(&mut self, already_parsed_attrs: Option>) diff --git a/src/test/compile-fail/macro-attribute.rs b/src/test/compile-fail/macro-attribute.rs new file mode 100644 index 00000000000..52f867fe913 --- /dev/null +++ b/src/test/compile-fail/macro-attribute.rs @@ -0,0 +1,12 @@ +// Copyright 2014 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. + +#[doc = $not_there] //~ error: unexpected token: `$` +fn main() { } diff --git a/src/test/compile-fail/malformed-derive-entry.rs b/src/test/compile-fail/malformed-derive-entry.rs index 62dbc21495a..ac000628f2b 100644 --- a/src/test/compile-fail/malformed-derive-entry.rs +++ b/src/test/compile-fail/malformed-derive-entry.rs @@ -9,11 +9,11 @@ // except according to those terms. #[derive(Copy(Bad))] -//~^ ERROR malformed `derive` entry +//~^ ERROR expected one of `)`, `,`, or `::`, found `(` struct Test1; #[derive(Copy="bad")] -//~^ ERROR malformed `derive` entry +//~^ ERROR expected one of `)`, `,`, or `::`, found `=` struct Test2; #[derive()] diff --git a/src/test/compile-fail/suffixed-literal-meta.rs b/src/test/compile-fail/suffixed-literal-meta.rs new file mode 100644 index 00000000000..bf55b7bdcb1 --- /dev/null +++ b/src/test/compile-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. + +#![feature(attr_literals)] + +#[path = 1usize] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1u8] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1u16] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1u32] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1u64] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1isize] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1i8] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1i16] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1i32] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1i64] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1.0f32] //~ ERROR: suffixed literals are not allowed in attributes +#[path = 1.0f64] //~ ERROR: suffixed literals are not allowed in attributes +fn main() { } diff --git a/src/test/parse-fail/attr-bad-meta.rs b/src/test/parse-fail/attr-bad-meta.rs index 092adbf29e3..d57a813311b 100644 --- a/src/test/parse-fail/attr-bad-meta.rs +++ b/src/test/parse-fail/attr-bad-meta.rs @@ -8,10 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z parse-only - -// error-pattern:expected one of `=` or `]` - // asterisk is bogus -#[attr*] +#[path*] //~ ERROR expected one of `(` or `=` mod m {} diff --git a/src/test/parse-fail/macro-attribute.rs b/src/test/parse-fail/macro-attribute.rs deleted file mode 100644 index 18add7d011c..00000000000 --- a/src/test/parse-fail/macro-attribute.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2014 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 - -#[doc = $not_there] //~ error: unexpected token: `$` -fn main() { } diff --git a/src/test/parse-fail/suffixed-literal-meta.rs b/src/test/parse-fail/suffixed-literal-meta.rs deleted file mode 100644 index 0e2840c69d3..00000000000 --- a/src/test/parse-fail/suffixed-literal-meta.rs +++ /dev/null @@ -1,25 +0,0 @@ -// 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/ui/span/E0536.stderr b/src/test/ui/span/E0536.stderr index c33b89953e2..b2da0c6a296 100644 --- a/src/test/ui/span/E0536.stderr +++ b/src/test/ui/span/E0536.stderr @@ -2,7 +2,7 @@ error[E0536]: expected 1 cfg-pattern --> $DIR/E0536.rs:11:7 | 11 | #[cfg(not())] //~ ERROR E0536 - | ^^^^^ + | ^^^ error: aborting due to previous error diff --git a/src/test/ui/span/E0537.stderr b/src/test/ui/span/E0537.stderr index 9d66ddbaae3..29873943f44 100644 --- a/src/test/ui/span/E0537.stderr +++ b/src/test/ui/span/E0537.stderr @@ -2,7 +2,7 @@ error[E0537]: invalid predicate `unknown` --> $DIR/E0537.rs:11:7 | 11 | #[cfg(unknown())] //~ ERROR E0537 - | ^^^^^^^^^ + | ^^^^^^^ error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From e3b8550a601ca920284f91ceff30a29340832fe7 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Mon, 13 Mar 2017 19:07:47 -0700 Subject: Point out correct turbofish usage on `Foo>` Whenever we parse a chain of binary operations, as long as the first operation is `<` and the subsequent operations are either `>` or `<`, present the following diagnostic help: use `::<...>` instead of `<...>` if you meant to specify type arguments This will lead to spurious recommendations on situations like `2 < 3 < 4` but should be clear from context that the help doesn't apply in that case. --- src/libsyntax/parse/parser.rs | 5 ++++- src/test/ui/did_you_mean/issue-40396.rs | 23 +++++++++++++++++++ src/test/ui/did_you_mean/issue-40396.stderr | 34 +++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/did_you_mean/issue-40396.rs create mode 100644 src/test/ui/did_you_mean/issue-40396.stderr (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 8f66c1a2b8c..208db839144 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2919,7 +2919,10 @@ impl<'a> Parser<'a> { let op_span = mk_sp(op.span.lo, self.span.hi); let mut err = self.diagnostic().struct_span_err(op_span, "chained comparison operators require parentheses"); - if op.node == BinOpKind::Lt && *outer_op == AssocOp::Greater { + if op.node == BinOpKind::Lt && + *outer_op == AssocOp::Less || // Include `<` to provide this recommendation + *outer_op == AssocOp::Greater // even in a case like the following: + { // Foo>> err.help( "use `::<...>` instead of `<...>` if you meant to specify type arguments"); } diff --git a/src/test/ui/did_you_mean/issue-40396.rs b/src/test/ui/did_you_mean/issue-40396.rs new file mode 100644 index 00000000000..1eae180976a --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40396.rs @@ -0,0 +1,23 @@ +// Copyright 2017 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. + +fn foo() { + println!("{:?}", (0..13).collect>()); +} + +fn bar() { + println!("{:?}", Vec::new()); +} + +fn qux() { + println!("{:?}", (0..13).collect()); +} + +fn main() {} diff --git a/src/test/ui/did_you_mean/issue-40396.stderr b/src/test/ui/did_you_mean/issue-40396.stderr new file mode 100644 index 00000000000..1a0c74dc01a --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40396.stderr @@ -0,0 +1,34 @@ +error: chained comparison operators require parentheses + --> $DIR/issue-40396.rs:12:37 + | +12 | println!("{:?}", (0..13).collect>()); + | ^^^^^^^^ + | + = help: use `::<...>` instead of `<...>` if you meant to specify type arguments + +error: chained comparison operators require parentheses + --> $DIR/issue-40396.rs:16:25 + | +16 | println!("{:?}", Vec::new()); + | ^^^^^^^ + | + = help: use `::<...>` instead of `<...>` if you meant to specify type arguments + +error: chained comparison operators require parentheses + --> $DIR/issue-40396.rs:20:37 + | +20 | println!("{:?}", (0..13).collect()); + | ^^^^^^^^ + | + = help: use `::<...>` instead of `<...>` if you meant to specify type arguments + +error: chained comparison operators require parentheses + --> $DIR/issue-40396.rs:20:41 + | +20 | println!("{:?}", (0..13).collect()); + | ^^^^^^ + | + = help: use `::<...>` instead of `<...>` if you meant to specify type arguments + +error: aborting due to 4 previous errors + -- cgit 1.4.1-3-g733a5 From 8eaac0843eb206c37b52db9d96094503487cd076 Mon Sep 17 00:00:00 2001 From: topecongiro Date: Fri, 17 Mar 2017 09:03:52 +0900 Subject: Parse 0e+10 as a valid floating-point literal Fixes issue #40408. --- src/libsyntax/parse/lexer/mod.rs | 2 +- src/test/run-pass/issue-40408.rs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/issue-40408.rs (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index de8a87e3a2b..d48cf6911ed 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -725,7 +725,7 @@ impl<'a> StringReader<'a> { base = 16; num_digits = self.scan_digits(16, 16); } - '0'...'9' | '_' | '.' => { + '0'...'9' | '_' | '.' | 'e' | 'E' => { num_digits = self.scan_digits(10, 10) + 1; } _ => { diff --git a/src/test/run-pass/issue-40408.rs b/src/test/run-pass/issue-40408.rs new file mode 100644 index 00000000000..a73dc1966b4 --- /dev/null +++ b/src/test/run-pass/issue-40408.rs @@ -0,0 +1,16 @@ +// Copyright 2017 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. + +fn main() { + println!("{}", 0E+10); + println!("{}", 0e+10); + println!("{}", 00e+10); + println!("{}", 00E+10); +} -- cgit 1.4.1-3-g733a5 From b5e889791a5ec8cb06224cf07273be8c84192698 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 17 Mar 2017 00:47:32 +0300 Subject: Refactor parsing of trait object types --- src/libsyntax/ast.rs | 12 +- src/libsyntax/ext/expand.rs | 2 +- src/libsyntax/ext/quote.rs | 2 +- src/libsyntax/ext/tt/macro_parser.rs | 2 +- src/libsyntax/parse/parser.rs | 404 +++++++++------------ src/libsyntax/parse/token.rs | 44 ++- src/test/compile-fail/E0178.rs | 3 - src/test/compile-fail/issue-34334.rs | 2 +- .../privacy/restricted/tuple-struct-fields/test.rs | 4 +- .../restricted/tuple-struct-fields/test2.rs | 4 +- .../restricted/tuple-struct-fields/test3.rs | 4 +- .../compile-fail/trait-object-macro-matcher.rs | 19 + ...t-object-reference-without-parens-suggestion.rs | 3 +- src/test/parse-fail/bounds-obj-parens.rs | 2 +- src/test/parse-fail/issue-17904.rs | 2 +- src/test/parse-fail/removed-syntax-ptr-lifetime.rs | 2 +- src/test/parse-fail/removed-syntax-uniq-mut-ty.rs | 2 +- src/test/parse-fail/trailing-plus-in-bounds.rs | 6 +- src/test/parse-fail/trait-object-macro-matcher.rs | 20 + .../parse-fail/trait-object-polytrait-priority.rs | 19 + src/test/run-pass/issue-28279.rs | 3 +- 21 files changed, 294 insertions(+), 267 deletions(-) create mode 100644 src/test/compile-fail/trait-object-macro-matcher.rs create mode 100644 src/test/parse-fail/trait-object-macro-matcher.rs create mode 100644 src/test/parse-fail/trait-object-polytrait-priority.rs (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 84fb69a7f10..4347046b6b8 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -17,7 +17,7 @@ pub use self::PathParameters::*; pub use symbol::Symbol as Name; pub use util::ThinVec; -use syntax_pos::{mk_sp, Span, DUMMY_SP, ExpnId}; +use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP, ExpnId}; use codemap::{respan, Spanned}; use abi::Abi; use ext::hygiene::SyntaxContext; @@ -1716,6 +1716,16 @@ pub struct PolyTraitRef { pub span: Span, } +impl PolyTraitRef { + pub fn new(lifetimes: Vec, path: Path, lo: BytePos, hi: BytePos) -> Self { + PolyTraitRef { + bound_lifetimes: lifetimes, + trait_ref: TraitRef { path: path, ref_id: DUMMY_NODE_ID }, + span: mk_sp(lo, hi), + } + } +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Visibility { Public, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index c1816582bc6..6abeb4b0b28 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -657,7 +657,7 @@ impl<'a> Parser<'a> { } ExpansionKind::Expr => Expansion::Expr(self.parse_expr()?), ExpansionKind::OptExpr => Expansion::OptExpr(Some(self.parse_expr()?)), - ExpansionKind::Ty => Expansion::Ty(self.parse_ty_no_plus()?), + ExpansionKind::Ty => Expansion::Ty(self.parse_ty()?), ExpansionKind::Pat => Expansion::Pat(self.parse_pat()?), }) } diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 10b7249743b..d7a85baa3ff 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -414,7 +414,7 @@ pub fn parse_arm_panic(parser: &mut Parser) -> Arm { } pub fn parse_ty_panic(parser: &mut Parser) -> P { - panictry!(parser.parse_ty_no_plus()) + panictry!(parser.parse_ty()) } pub fn parse_stmt_panic(parser: &mut Parser) -> Option { diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 6385d206a0c..ed17f0f956c 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -512,7 +512,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { }, "pat" => token::NtPat(panictry!(p.parse_pat())), "expr" => token::NtExpr(panictry!(p.parse_expr())), - "ty" => token::NtTy(panictry!(p.parse_ty_no_plus())), + "ty" => token::NtTy(panictry!(p.parse_ty())), // this could be handled like a token, since it is one "ident" => match p.token { token::Ident(sn) => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 0a97accead6..df4ccc94c04 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -41,7 +41,7 @@ use ast::{BinOpKind, UnOp}; use ast::RangeEnd; use {ast, attr}; use codemap::{self, CodeMap, Spanned, spanned, respan}; -use syntax_pos::{self, Span, Pos, BytePos, mk_sp}; +use syntax_pos::{self, Span, BytePos, mk_sp}; use errors::{self, DiagnosticBuilder}; use parse::{self, classify, token}; use parse::common::SeqSep; @@ -1116,57 +1116,13 @@ impl<'a> Parser<'a> { self.check_keyword(keywords::Extern) } - pub fn get_lifetime(&mut self) -> ast::Ident { + fn get_label(&mut self) -> ast::Ident { match self.token { token::Lifetime(ref ident) => *ident, _ => self.bug("not a lifetime"), } } - pub fn parse_for_in_type(&mut self) -> PResult<'a, TyKind> { - /* - Parses whatever can come after a `for` keyword in a type. - The `for` hasn't been consumed. - - - for <'lt> [unsafe] [extern "ABI"] fn (S) -> T - - for <'lt> path::foo(a, b) + Trait + 'a - */ - - let lo = self.span.lo; - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - - // examine next token to decide to do - if self.token_is_bare_fn_keyword() { - self.parse_ty_bare_fn(lifetime_defs) - } else { - let hi = self.span.hi; - let trait_ref = self.parse_trait_ref()?; - let poly_trait_ref = PolyTraitRef { bound_lifetimes: lifetime_defs, - trait_ref: trait_ref, - span: mk_sp(lo, hi)}; - let other_bounds = if self.eat(&token::BinOp(token::Plus)) { - self.parse_ty_param_bounds()? - } else { - Vec::new() - }; - let all_bounds = - Some(TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)).into_iter() - .chain(other_bounds) - .collect(); - Ok(ast::TyKind::TraitObject(all_bounds)) - } - } - - pub fn parse_impl_trait_type(&mut self) -> PResult<'a, TyKind> { - // Parses whatever can come after a `impl` keyword in a type. - // The `impl` has already been consumed. - Ok(ast::TyKind::ImplTrait(self.parse_ty_param_bounds()?)) - } - - pub fn parse_ty_path(&mut self) -> PResult<'a, TyKind> { - Ok(TyKind::Path(None, self.parse_path(PathStyle::Type)?)) - } - /// parse a TyKind::BareFn type: pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec) -> PResult<'a, TyKind> { @@ -1347,84 +1303,9 @@ impl<'a> Parser<'a> { } } - /// Parse a type. + // Parse a type pub fn parse_ty(&mut self) -> PResult<'a, P> { - let lo = self.span.lo; - let lhs = self.parse_ty_no_plus()?; - - if !self.eat(&token::BinOp(token::Plus)) { - return Ok(lhs); - } - - let mut bounds = self.parse_ty_param_bounds()?; - - // In type grammar, `+` is treated like a binary operator, - // and hence both L and R side are required. - if bounds.is_empty() { - let prev_span = self.prev_span; - self.span_err(prev_span, - "at least one type parameter bound \ - must be specified"); - } - - let mut lhs = lhs.unwrap(); - if let TyKind::Paren(ty) = lhs.node { - // We have to accept the first bound in parens for backward compatibility. - // Example: `(Bound) + Bound + Bound` - lhs = ty.unwrap(); - } - if let TyKind::Path(None, path) = lhs.node { - let poly_trait_ref = PolyTraitRef { - bound_lifetimes: Vec::new(), - trait_ref: TraitRef { path: path, ref_id: lhs.id }, - span: lhs.span, - }; - let poly_trait_ref = TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None); - bounds.insert(0, poly_trait_ref); - } else { - let mut err = struct_span_err!(self.sess.span_diagnostic, lhs.span, E0178, - "expected a path on the left-hand side \ - of `+`, not `{}`", - pprust::ty_to_string(&lhs)); - err.span_label(lhs.span, &format!("expected a path")); - let hi = bounds.iter().map(|x| match *x { - TraitTyParamBound(ref tr, _) => tr.span.hi, - RegionTyParamBound(ref r) => r.span.hi, - }).max_by_key(|x| x.to_usize()); - let full_span = hi.map(|hi| Span { - lo: lhs.span.lo, - hi: hi, - expn_id: lhs.span.expn_id, - }); - match (&lhs.node, full_span) { - (&TyKind::Rptr(ref lifetime, ref mut_ty), Some(full_span)) => { - let ty_str = pprust::to_string(|s| { - use print::pp::word; - use print::pprust::PrintState; - - word(&mut s.s, "&")?; - s.print_opt_lifetime(lifetime)?; - s.print_mutability(mut_ty.mutbl)?; - s.popen()?; - s.print_type(&mut_ty.ty)?; - s.print_bounds(" +", &bounds)?; - s.pclose() - }); - err.span_suggestion(full_span, "try adding parentheses (per RFC 438):", - ty_str); - } - - _ => { - help!(&mut err, - "perhaps you forgot parentheses? (per RFC 438)"); - } - } - err.emit(); - } - - let sp = mk_sp(lo, self.prev_span.hi); - let sum = TyKind::TraitObject(bounds); - Ok(P(Ty {id: ast::DUMMY_NODE_ID, node: sum, span: sp})) + self.parse_ty_common(true) } /// Parse a type in restricted contexts where `+` is not permitted. @@ -1432,15 +1313,17 @@ impl<'a> Parser<'a> { /// `+` is prohibited to maintain operator priority (P(+) < P(&)). /// Example 2: `value1 as TYPE + value2` /// `+` is prohibited to avoid interactions with expression grammar. - pub fn parse_ty_no_plus(&mut self) -> PResult<'a, P> { + fn parse_ty_no_plus(&mut self) -> PResult<'a, P> { + self.parse_ty_common(false) + } + + fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P> { maybe_whole!(self, NtTy, |x| x); let lo = self.span.lo; - - let t = if self.eat(&token::OpenDelim(token::Paren)) { - // (t) is a parenthesized ty - // (t,) is the type of a tuple with only one field, - // of type t + let node = if self.eat(&token::OpenDelim(token::Paren)) { + // `(TYPE)` is a parenthesized type. + // `(TYPE,)` is a tuple with a single field of type TYPE. let mut ts = vec![]; let mut last_comma = false; while self.token != token::CloseDelim(token::Paren) { @@ -1452,81 +1335,162 @@ impl<'a> Parser<'a> { break; } } - self.expect(&token::CloseDelim(token::Paren))?; + if ts.len() == 1 && !last_comma { - TyKind::Paren(ts.into_iter().nth(0).unwrap()) + let ty = ts.into_iter().nth(0).unwrap().unwrap(); + match ty.node { + // Accept `(Trait1) + Trait2 + 'a` for backward compatibility (#39318). + TyKind::Path(None, ref path) + if allow_plus && self.token == token::BinOp(token::Plus) => { + self.bump(); // `+` + let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo, self.prev_span.hi); + let mut bounds = vec![TraitTyParamBound(pt, TraitBoundModifier::None)]; + bounds.append(&mut self.parse_ty_param_bounds()?); + TyKind::TraitObject(bounds) + } + _ => TyKind::Paren(P(ty)) + } } else { TyKind::Tup(ts) } } else if self.eat(&token::Not) { + // Never type `!` TyKind::Never } else if self.eat(&token::BinOp(token::Star)) { - // STAR POINTER (bare pointer?) + // Raw pointer TyKind::Ptr(self.parse_ptr()?) } else if self.eat(&token::OpenDelim(token::Bracket)) { - // VECTOR + // Array or slice let t = self.parse_ty()?; - - // Parse the `; e` in `[ i32; e ]` - // where `e` is a const expression + // Parse optional `; EXPR` in `[TYPE; EXPR]` let t = match self.maybe_parse_fixed_length_of_vec()? { None => TyKind::Slice(t), - Some(suffix) => TyKind::Array(t, suffix) + Some(suffix) => TyKind::Array(t, suffix), }; self.expect(&token::CloseDelim(token::Bracket))?; t - } else if self.check(&token::BinOp(token::And)) || - self.check(&token::AndAnd) { - // BORROWED POINTER + } else if self.check(&token::BinOp(token::And)) || self.check(&token::AndAnd) { + // Reference self.expect_and()?; self.parse_borrowed_pointee()? - } else if self.check_keyword(keywords::For) { - // FIXME `+` has incorrect priority in trait object types starting with `for` (#39317). - self.parse_for_in_type()? - } else if self.eat_keyword(keywords::Impl) { - // FIXME figure out priority of `+` in `impl Trait1 + Trait2` (#34511). - self.parse_impl_trait_type()? - } else if self.token_is_bare_fn_keyword() { - // BARE FUNCTION - self.parse_ty_bare_fn(Vec::new())? } else if self.eat_keyword_noexpect(keywords::Typeof) { - // TYPEOF + // `typeof(EXPR)` // In order to not be ambiguous, the type must be surrounded by parens. self.expect(&token::OpenDelim(token::Paren))?; let e = self.parse_expr()?; self.expect(&token::CloseDelim(token::Paren))?; TyKind::Typeof(e) + } else if self.eat(&token::Underscore) { + // A type to be inferred `_` + TyKind::Infer } else if self.eat_lt() { + // Qualified path let (qself, path) = self.parse_qualified_path(PathStyle::Type)?; TyKind::Path(Some(qself), path) } else if self.token.is_path_start() { + // Simple path let path = self.parse_path(PathStyle::Type)?; if self.eat(&token::Not) { - // MACRO INVOCATION + // Macro invocation in type position let (_, tts) = self.expect_delimited_token_tree()?; - let hi = self.span.hi; - TyKind::Mac(spanned(lo, hi, Mac_ { path: path, tts: tts })) + TyKind::Mac(spanned(lo, self.span.hi, Mac_ { path: path, tts: tts })) } else { - // NAMED TYPE - TyKind::Path(None, path) + // Just a type path or bound list (trait object type) starting with a trait. + // `Type` + // `Trait1 + Trait2 + 'a` + if allow_plus && self.eat(&token::BinOp(token::Plus)) { + let poly_trait = PolyTraitRef::new(Vec::new(), path, lo, self.prev_span.hi); + let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)]; + bounds.append(&mut self.parse_ty_param_bounds()?); + TyKind::TraitObject(bounds) + } else { + TyKind::Path(None, path) + } } - } else if self.eat(&token::Underscore) { - // TYPE TO BE INFERRED - TyKind::Infer + } else if self.token_is_bare_fn_keyword() { + // Function pointer type + self.parse_ty_bare_fn(Vec::new())? + } else if self.check_keyword(keywords::For) { + // Function pointer type or bound list (trait object type) starting with a poly-trait. + // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` + // `for<'lt> Trait1<'lt> + Trait2 + 'a` + let lo = self.span.lo; + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + if self.token_is_bare_fn_keyword() { + self.parse_ty_bare_fn(lifetime_defs)? + } else { + let path = self.parse_path(PathStyle::Type)?; + let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo, self.prev_span.hi); + let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)]; + if allow_plus && self.eat(&token::BinOp(token::Plus)) { + bounds.append(&mut self.parse_ty_param_bounds()?) + } + TyKind::TraitObject(bounds) + } + } else if self.eat_keyword(keywords::Impl) { + // FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511). + TyKind::ImplTrait(self.parse_ty_param_bounds()?) + } else if self.check(&token::Question) { + // Bound list (trait object type) + // Bound lists starting with `'lt` are not currently supported (#40043) + TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?) } else { let msg = format!("expected type, found {}", self.this_token_descr()); return Err(self.fatal(&msg)); }; - let sp = mk_sp(lo, self.prev_span.hi); - Ok(P(Ty {id: ast::DUMMY_NODE_ID, node: t, span: sp})) + let span = mk_sp(lo, self.prev_span.hi); + let ty = Ty { node: node, span: span, id: ast::DUMMY_NODE_ID }; + + // Try to recover from use of `+` with incorrect priority. + self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?; + + Ok(P(ty)) } - pub fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { - // look for `&'lt` or `&'foo ` and interpret `foo` as the region name: - let opt_lifetime = self.eat_lifetime(); - let mutbl = self.parse_mutability()?; + fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> { + // Do not add `+` to expected tokens. + if !allow_plus || self.token != token::BinOp(token::Plus) { + return Ok(()) + } + + self.bump(); // `+` + let bounds = self.parse_ty_param_bounds()?; + let sum_span = mk_sp(ty.span.lo, self.prev_span.hi); + + let mut err = struct_span_err!(self.sess.span_diagnostic, ty.span, E0178, + "expected a path on the left-hand side of `+`, not `{}`", pprust::ty_to_string(&ty)); + err.span_label(ty.span, &format!("expected a path")); + + match ty.node { + TyKind::Rptr(ref lifetime, ref mut_ty) => { + let sum_with_parens = pprust::to_string(|s| { + use print::pp::word; + use print::pprust::PrintState; + + word(&mut s.s, "&")?; + s.print_opt_lifetime(lifetime)?; + s.print_mutability(mut_ty.mutbl)?; + s.popen()?; + s.print_type(&mut_ty.ty)?; + s.print_bounds(" +", &bounds)?; + s.pclose() + }); + err.span_suggestion(sum_span, "try adding parentheses:", sum_with_parens); + } + TyKind::Ptr(..) | TyKind::BareFn(..) => { + help!(&mut err, "perhaps you forgot parentheses?"); + } + _ => {} + } + err.emit(); + Ok(()) + } + + fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { + let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; + let mutbl = self.parse_mutability(); let ty = self.parse_ty_no_plus()?; return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty: ty, mutbl: mutbl })); } @@ -1927,30 +1891,28 @@ impl<'a> Parser<'a> { } } - /// Parse single lifetime 'a or nothing. - pub fn eat_lifetime(&mut self) -> Option { + fn check_lifetime(&mut self) -> bool { + self.expected_tokens.push(TokenType::Lifetime); + self.token.is_lifetime() + } + + /// Parse single lifetime 'a or panic. + fn expect_lifetime(&mut self) -> Lifetime { match self.token { token::Lifetime(ident) => { self.bump(); - Some(Lifetime { - id: ast::DUMMY_NODE_ID, - span: self.prev_span, - name: ident.name - }) - } - _ => { - self.expected_tokens.push(TokenType::Lifetime); - None + Lifetime { name: ident.name, span: self.prev_span, id: ast::DUMMY_NODE_ID } } + _ => self.span_bug(self.span, "not a lifetime") } } /// Parse mutability (`mut` or nothing). - pub fn parse_mutability(&mut self) -> PResult<'a, Mutability> { + fn parse_mutability(&mut self) -> Mutability { if self.eat_keyword(keywords::Mut) { - Ok(Mutability::Mutable) + Mutability::Mutable } else { - Ok(Mutability::Immutable) + Mutability::Immutable } } @@ -2207,7 +2169,7 @@ impl<'a> Parser<'a> { return self.parse_while_expr(None, lo, attrs); } if self.token.is_lifetime() { - let label = Spanned { node: self.get_lifetime(), + let label = Spanned { node: self.get_label(), span: self.span }; let lo = self.span.lo; self.bump(); @@ -2230,7 +2192,7 @@ impl<'a> Parser<'a> { if self.eat_keyword(keywords::Continue) { let ex = if self.token.is_lifetime() { let ex = ExprKind::Continue(Some(Spanned{ - node: self.get_lifetime(), + node: self.get_label(), span: self.span })); self.bump(); @@ -2267,7 +2229,7 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(keywords::Break) { let lt = if self.token.is_lifetime() { let spanned_lt = Spanned { - node: self.get_lifetime(), + node: self.get_label(), span: self.span }; self.bump(); @@ -2700,7 +2662,7 @@ impl<'a> Parser<'a> { } token::BinOp(token::And) | token::AndAnd => { self.expect_and()?; - let m = self.parse_mutability()?; + let m = self.parse_mutability(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; hi = span.hi; @@ -3422,7 +3384,7 @@ impl<'a> Parser<'a> { token::BinOp(token::And) | token::AndAnd => { // Parse &pat / &mut pat self.expect_and()?; - let mutbl = self.parse_mutability()?; + let mutbl = self.parse_mutability(); if let token::Lifetime(ident) = self.token { return Err(self.fatal(&format!("unexpected lifetime `{}` in pattern", ident))); } @@ -3449,7 +3411,7 @@ impl<'a> Parser<'a> { pat = self.parse_pat_ident(BindingMode::ByValue(Mutability::Mutable))?; } else if self.eat_keyword(keywords::Ref) { // Parse ref ident @ pat / ref mut ident @ pat - let mutbl = self.parse_mutability()?; + let mutbl = self.parse_mutability(); pat = self.parse_pat_ident(BindingMode::ByRef(mutbl))?; } else if self.eat_keyword(keywords::Box) { // Parse box pat @@ -4069,30 +4031,32 @@ impl<'a> Parser<'a> { // BOUND = TY_BOUND | LT_BOUND // LT_BOUND = LIFETIME (e.g. `'a`) // TY_BOUND = [?] [for] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) - fn parse_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds> - { + fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> { let mut bounds = Vec::new(); loop { let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; - if let Some(lifetime) = self.eat_lifetime() { + if self.check_lifetime() { if let Some(question_span) = question { self.span_err(question_span, "`?` may only modify trait bounds, not lifetime bounds"); } - bounds.push(RegionTyParamBound(lifetime)); - } else {if self.check_keyword(keywords::For) || self.check_path() { - let poly_trait_ref = self.parse_poly_trait_ref()?; + bounds.push(RegionTyParamBound(self.expect_lifetime())); + } else if self.check_keyword(keywords::For) || self.check_path() { + let lo = self.span.lo; + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let path = self.parse_path(PathStyle::Type)?; + let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo, self.prev_span.hi); let modifier = if question.is_some() { TraitBoundModifier::Maybe } else { TraitBoundModifier::None }; - bounds.push(TraitTyParamBound(poly_trait_ref, modifier)); + bounds.push(TraitTyParamBound(poly_trait, modifier)); } else { break - }} + } - if !self.eat(&token::BinOp(token::Plus)) { + if !allow_plus || !self.eat(&token::BinOp(token::Plus)) { break } } @@ -4100,12 +4064,16 @@ impl<'a> Parser<'a> { return Ok(bounds); } + fn parse_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds> { + self.parse_ty_param_bounds_common(true) + } + // Parse bounds of a type parameter `BOUND + BOUND + BOUND` without trailing `+`. // BOUND = LT_BOUND (e.g. `'a`) fn parse_lt_param_bounds(&mut self) -> Vec { let mut lifetimes = Vec::new(); - while let Some(lifetime) = self.eat_lifetime() { - lifetimes.push(lifetime); + while self.check_lifetime() { + lifetimes.push(self.expect_lifetime()); if !self.eat(&token::BinOp(token::Plus)) { break @@ -4150,7 +4118,8 @@ impl<'a> Parser<'a> { let mut seen_ty_param = false; loop { let attrs = self.parse_outer_attributes()?; - if let Some(lifetime) = self.eat_lifetime() { + if self.check_lifetime() { + let lifetime = self.expect_lifetime(); // Parse lifetime parameter. let bounds = if self.eat(&token::Colon) { self.parse_lt_param_bounds() @@ -4166,7 +4135,7 @@ impl<'a> Parser<'a> { self.span_err(self.prev_span, "lifetime parameters must be declared prior to type parameters"); } - } else {if self.check_ident() { + } else if self.check_ident() { // Parse type parameter. ty_params.push(self.parse_ty_param(attrs)?); seen_ty_param = true; @@ -4178,7 +4147,7 @@ impl<'a> Parser<'a> { &format!("trailing attribute after {} parameters", param_kind)); } break - }} + } if !self.eat(&token::Comma) { break @@ -4224,14 +4193,14 @@ impl<'a> Parser<'a> { let mut seen_type = false; let mut seen_binding = false; loop { - if let Some(lifetime) = self.eat_lifetime() { + if self.check_lifetime() && self.look_ahead(1, |t| t != &token::BinOp(token::Plus)) { // Parse lifetime argument. - lifetimes.push(lifetime); + lifetimes.push(self.expect_lifetime()); if seen_type || seen_binding { self.span_err(self.prev_span, "lifetime parameters must be declared prior to type parameters"); } - } else {if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) { + } else if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) { // Parse associated type binding. let lo = self.span.lo; let ident = self.parse_ident()?; @@ -4254,7 +4223,7 @@ impl<'a> Parser<'a> { seen_type = true; } else { break - }} + } if !self.eat(&token::Comma) { break @@ -4299,7 +4268,8 @@ impl<'a> Parser<'a> { loop { let lo = self.span.lo; - if let Some(lifetime) = self.eat_lifetime() { + if self.check_lifetime() && self.look_ahead(1, |t| t != &token::BinOp(token::Plus)) { + let lifetime = self.expect_lifetime(); // Bounds starting with a colon are mandatory, but possibly empty. self.expect(&token::Colon)?; let bounds = self.parse_lt_param_bounds(); @@ -4310,7 +4280,7 @@ impl<'a> Parser<'a> { bounds: bounds, } )); - } else {if self.check_type() { + } else if self.check_type() { // Parse optional `for<'a, 'b>`. // This `for` is parsed greedily and applies to the whole predicate, // the bounded type can have its own `for` applying only to it. @@ -4348,7 +4318,7 @@ impl<'a> Parser<'a> { } } else { break - }} + } if !self.eat(&token::Comma) { break @@ -4453,13 +4423,13 @@ impl<'a> Parser<'a> { } else if self.look_ahead(1, |t| t.is_lifetime()) && isolated_self(self, 2) { self.bump(); - let lt = self.eat_lifetime().expect("not a lifetime"); + let lt = self.expect_lifetime(); (SelfKind::Region(Some(lt), Mutability::Immutable), expect_ident(self)) } else if self.look_ahead(1, |t| t.is_lifetime()) && self.look_ahead(2, |t| t.is_keyword(keywords::Mut)) && isolated_self(self, 3) { self.bump(); - let lt = self.eat_lifetime().expect("not a lifetime"); + let lt = self.expect_lifetime(); self.bump(); (SelfKind::Region(Some(lt), Mutability::Mutable), expect_ident(self)) } else { @@ -4852,14 +4822,6 @@ impl<'a> Parser<'a> { } } - /// Parse a::B - fn parse_trait_ref(&mut self) -> PResult<'a, TraitRef> { - Ok(TraitRef { - path: self.parse_path(PathStyle::Type)?, - ref_id: ast::DUMMY_NODE_ID, - }) - } - fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { if self.eat_keyword(keywords::For) { self.expect_lt()?; @@ -4875,18 +4837,6 @@ impl<'a> Parser<'a> { } } - /// Parse for<'l> a::B - fn parse_poly_trait_ref(&mut self) -> PResult<'a, PolyTraitRef> { - let lo = self.span.lo; - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - - Ok(PolyTraitRef { - bound_lifetimes: lifetime_defs, - trait_ref: self.parse_trait_ref()?, - span: mk_sp(lo, self.prev_span.hi), - }) - } - /// Parse struct Foo { ... } fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 75852629ce1..519d5bd98e4 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -103,6 +103,21 @@ fn ident_can_begin_expr(ident: ast::Ident) -> bool { ].contains(&ident.name) } +fn ident_can_begin_type(ident: ast::Ident) -> bool { + let ident_token: Token = Ident(ident); + + !ident_token.is_any_keyword() || + ident_token.is_path_segment_keyword() || + [ + keywords::For.name(), + keywords::Impl.name(), + keywords::Fn.name(), + keywords::Unsafe.name(), + keywords::Extern.name(), + keywords::Typeof.name(), + ].contains(&ident.name) +} + #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug)] pub enum Token { /* Expression-operator symbols. */ @@ -182,23 +197,21 @@ impl Token { /// Returns `true` if the token can appear at the start of an expression. pub fn can_begin_expr(&self) -> bool { match *self { - OpenDelim(..) => true, - Ident(ident) => ident_can_begin_expr(ident), - Literal(..) => true, - Not => true, - BinOp(Minus) => true, - BinOp(Star) => true, - BinOp(And) => true, - BinOp(Or) => true, // in lambda syntax - OrOr => true, // in lambda syntax - AndAnd => true, // double borrow + Ident(ident) => ident_can_begin_expr(ident), // value name or keyword + OpenDelim(..) => true, // tuple, array or block + Literal(..) => true, // literal + Not => true, // operator not + BinOp(Minus) => true, // unary minus + BinOp(Star) => true, // dereference + BinOp(Or) | OrOr => true, // closure + BinOp(And) => true, // reference + AndAnd => true, // double reference DotDot | DotDotDot => true, // range notation Lt | BinOp(Shl) => true, // associated path - ModSep => true, - Pound => true, // for expression attributes + ModSep => true, // global path + Pound => true, // expression attributes Interpolated(ref nt) => match **nt { NtExpr(..) => true, - NtIdent(..) => true, NtBlock(..) => true, NtPath(..) => true, _ => false, @@ -210,19 +223,20 @@ impl Token { /// Returns `true` if the token can appear at the start of a type. pub fn can_begin_type(&self) -> bool { match *self { + Ident(ident) => ident_can_begin_type(ident), // type name or keyword OpenDelim(Paren) => true, // tuple OpenDelim(Bracket) => true, // array - Ident(..) => true, // type name or keyword Underscore => true, // placeholder Not => true, // never BinOp(Star) => true, // raw pointer BinOp(And) => true, // reference AndAnd => true, // double reference + Question => true, // maybe bound in trait object + Lifetime(..) => true, // lifetime bound in trait object Lt | BinOp(Shl) => true, // associated path ModSep => true, // global path Interpolated(ref nt) => match **nt { NtTy(..) => true, - NtIdent(..) => true, NtPath(..) => true, _ => false, }, diff --git a/src/test/compile-fail/E0178.rs b/src/test/compile-fail/E0178.rs index ffc5940c95c..6527465e0b7 100644 --- a/src/test/compile-fail/E0178.rs +++ b/src/test/compile-fail/E0178.rs @@ -17,15 +17,12 @@ struct Bar<'a> { x: &'a Foo + 'a, //~^ ERROR E0178 //~| NOTE expected a path - //~| ERROR at least one non-builtin trait is required for an object type y: &'a mut Foo + 'a, //~^ ERROR E0178 //~| NOTE expected a path - //~| ERROR at least one non-builtin trait is required for an object type z: fn() -> Foo + 'a, //~^ ERROR E0178 //~| NOTE expected a path - //~| ERROR at least one non-builtin trait is required for an object type } fn main() { diff --git a/src/test/compile-fail/issue-34334.rs b/src/test/compile-fail/issue-34334.rs index aff908e5815..95b5fabc81e 100644 --- a/src/test/compile-fail/issue-34334.rs +++ b/src/test/compile-fail/issue-34334.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main () { - let sr: Vec<(u32, _, _) = vec![]; //~ ERROR expected one of `+`, `,`, or `>`, found `=` + let sr: Vec<(u32, _, _) = vec![]; //~ ERROR expected one of `,` or `>`, found `=` let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); //~^ ERROR cannot find value `sr` in this scope } diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs index bb212b3114d..208f1a0e2ee 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs @@ -11,6 +11,6 @@ mod foo { type T = (); struct S1(pub(foo) (), pub(T), pub(crate) (), pub(((), T))); - struct S2(pub((foo)) ()); //~ ERROR expected one of `+` or `,`, found `(` - //~| ERROR expected one of `+`, `;`, or `where`, found `(` + struct S2(pub((foo)) ()); //~ ERROR expected `,`, found `(` + //~| ERROR expected one of `;` or `where`, found `(` } diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs index 2c6e71d7c55..57769646e3b 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs @@ -12,8 +12,8 @@ macro_rules! define_struct { ($t:ty) => { struct S1(pub $t); struct S2(pub (foo) ()); - struct S3(pub $t ()); //~ ERROR expected one of `+` or `,`, found `(` - //~| ERROR expected one of `+`, `;`, or `where`, found `(` + struct S3(pub $t ()); //~ ERROR expected `,`, found `(` + //~| ERROR expected one of `;` or `where`, found `(` } } diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs index e15eeae8159..db3358f7d50 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs @@ -12,8 +12,8 @@ macro_rules! define_struct { ($t:ty) => { struct S1(pub($t)); struct S2(pub (foo) ()); - struct S3(pub($t) ()); //~ ERROR expected one of `+` or `,`, found `(` - //~| ERROR expected one of `+`, `;`, or `where`, found `(` + struct S3(pub($t) ()); //~ ERROR expected `,`, found `(` + //~| ERROR expected one of `;` or `where`, found `(` } } diff --git a/src/test/compile-fail/trait-object-macro-matcher.rs b/src/test/compile-fail/trait-object-macro-matcher.rs new file mode 100644 index 00000000000..de80b04b865 --- /dev/null +++ b/src/test/compile-fail/trait-object-macro-matcher.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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. + +// `ty` matcher accepts trait object types + +macro_rules! m { + ($t: ty) => ( let _: $t; ) +} + +fn main() { + m!(Copy + Send + 'static); //~ ERROR the trait `std::marker::Copy` cannot be made into an object +} diff --git a/src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs b/src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs index c009644c561..f9f887b78b0 100644 --- a/src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs +++ b/src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs @@ -13,10 +13,9 @@ fn main() { //~^ ERROR expected a path //~| HELP try adding parentheses //~| SUGGESTION let _: &(Copy + 'static); - //~| ERROR at least one non-builtin trait is required for an object type + //~| ERROR the trait `std::marker::Copy` cannot be made into an object let _: &'static Copy + 'static; //~^ ERROR expected a path //~| HELP try adding parentheses //~| SUGGESTION let _: &'static (Copy + 'static); - //~| ERROR at least one non-builtin trait is required for an object type } diff --git a/src/test/parse-fail/bounds-obj-parens.rs b/src/test/parse-fail/bounds-obj-parens.rs index cbdffb4a255..ad59d4a52d7 100644 --- a/src/test/parse-fail/bounds-obj-parens.rs +++ b/src/test/parse-fail/bounds-obj-parens.rs @@ -10,6 +10,6 @@ // compile-flags: -Z parse-only -type A = Box<(Fn(D::Error) -> E) + 'static + Send + Sync>; // OK +type A = Box<(Fn(D::Error) -> E) + 'static + Send + Sync>; // OK (but see #39318) FAIL //~ ERROR diff --git a/src/test/parse-fail/issue-17904.rs b/src/test/parse-fail/issue-17904.rs index ae28ac76acb..a54d89f48c3 100644 --- a/src/test/parse-fail/issue-17904.rs +++ b/src/test/parse-fail/issue-17904.rs @@ -13,6 +13,6 @@ struct Baz where U: Eq(U); //This is parsed as the new Fn* style parenthesis syntax. struct Baz where U: Eq(U) -> R; // Notice this parses as well. struct Baz(U) where U: Eq; // This rightfully signals no error as well. -struct Foo where T: Copy, (T); //~ ERROR expected one of `+`, `:`, `==`, or `=`, found `;` +struct Foo where T: Copy, (T); //~ ERROR expected one of `:`, `==`, or `=`, found `;` fn main() {} diff --git a/src/test/parse-fail/removed-syntax-ptr-lifetime.rs b/src/test/parse-fail/removed-syntax-ptr-lifetime.rs index ebef0e56e3e..b91ab8730b3 100644 --- a/src/test/parse-fail/removed-syntax-ptr-lifetime.rs +++ b/src/test/parse-fail/removed-syntax-ptr-lifetime.rs @@ -10,4 +10,4 @@ // compile-flags: -Z parse-only -type bptr = &lifetime/isize; //~ ERROR expected one of `!`, `(`, `+`, `::`, `;`, or `<`, found `/` +type bptr = &lifetime/isize; //~ ERROR expected one of `!`, `(`, `::`, `;`, or `<`, found `/` diff --git a/src/test/parse-fail/removed-syntax-uniq-mut-ty.rs b/src/test/parse-fail/removed-syntax-uniq-mut-ty.rs index 9bd8dc9b11b..8a47376179d 100644 --- a/src/test/parse-fail/removed-syntax-uniq-mut-ty.rs +++ b/src/test/parse-fail/removed-syntax-uniq-mut-ty.rs @@ -10,4 +10,4 @@ // compile-flags: -Z parse-only -type mut_box = Box; //~ ERROR expected type, found keyword `mut` +type mut_box = Box; //~ ERROR expected one of `>`, lifetime, or type, found `mut` diff --git a/src/test/parse-fail/trailing-plus-in-bounds.rs b/src/test/parse-fail/trailing-plus-in-bounds.rs index 44bb1f930c7..4a2e6d5bdcd 100644 --- a/src/test/parse-fail/trailing-plus-in-bounds.rs +++ b/src/test/parse-fail/trailing-plus-in-bounds.rs @@ -13,7 +13,7 @@ use std::fmt::Debug; fn main() { - let x: Box = box 3 as Box; - //~^ ERROR at least one type parameter bound must be specified - //~^^ ERROR at least one type parameter bound must be specified + let x: Box = box 3 as Box; // Trailing `+` is OK } + +FAIL //~ ERROR diff --git a/src/test/parse-fail/trait-object-macro-matcher.rs b/src/test/parse-fail/trait-object-macro-matcher.rs new file mode 100644 index 00000000000..3a5bce509f1 --- /dev/null +++ b/src/test/parse-fail/trait-object-macro-matcher.rs @@ -0,0 +1,20 @@ +// Copyright 2017 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. + +// A single lifetime is not parsed as a type. +// `ty` matcher in particular doesn't accept a single lifetime + +macro_rules! m { + ($t: ty) => ( let _: $t; ) +} + +fn main() { + m!('static); //~ ERROR expected type, found `'static` +} diff --git a/src/test/parse-fail/trait-object-polytrait-priority.rs b/src/test/parse-fail/trait-object-polytrait-priority.rs new file mode 100644 index 00000000000..f0abc678c21 --- /dev/null +++ b/src/test/parse-fail/trait-object-polytrait-priority.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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. + +trait Trait<'a> {} + +fn main() { + let _: &for<'a> Trait<'a> + 'static; + //~^ ERROR expected a path on the left-hand side of `+`, not `& for<'a>Trait<'a>` + //~| NOTE expected a path + //~| HELP try adding parentheses + //~| SUGGESTION &( for<'a>Trait<'a> + 'static) +} diff --git a/src/test/run-pass/issue-28279.rs b/src/test/run-pass/issue-28279.rs index ae40ce44d17..3165084b9e9 100644 --- a/src/test/run-pass/issue-28279.rs +++ b/src/test/run-pass/issue-28279.rs @@ -18,7 +18,7 @@ fn test1() -> Rc Fn(&'a usize) + 'static> { } } -fn test2() -> *mut for<'a> Fn(&'a usize) + 'static { +fn test2() -> *mut (for<'a> Fn(&'a usize) + 'static) { if let Some(_) = Some(1) { loop{} } else { @@ -27,4 +27,3 @@ fn test2() -> *mut for<'a> Fn(&'a usize) + 'static { } fn main() {} - -- cgit 1.4.1-3-g733a5 From 769b95dc9f92edb51146727813ea7eae00b5b651 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Fri, 17 Mar 2017 21:13:00 -0700 Subject: Add diagnostic for incorrect `pub (restriction)` Given the following statement ```rust pub (a) fn afn() {} ``` Provide the following diagnostic: ```rust error: incorrect restriction in `pub` --> file.rs:15:1 | 15 | pub (a) fn afn() {} | ^^^^^^^ | = help: some valid visibility restrictions are: `pub(crate)`: visible only on the current crate `pub(super)`: visible only in the current module's parent `pub(in path::to::module)`: visible only on the specified path help: to make this visible only to module `a`, add `in` before the path: | pub (in a) fn afn() {} ``` Remove cruft from old `pub(path)` syntax. --- src/libsyntax/parse/parser.rs | 64 +++++++++++++--------- .../privacy/restricted/tuple-struct-fields/test.rs | 7 ++- .../restricted/tuple-struct-fields/test2.rs | 7 ++- .../restricted/tuple-struct-fields/test3.rs | 7 ++- src/test/ui/pub/pub-restricted-error-fn.rs | 13 +++++ src/test/ui/pub/pub-restricted-error-fn.stderr | 8 +++ src/test/ui/pub/pub-restricted-error.rs | 19 +++++++ src/test/ui/pub/pub-restricted-error.stderr | 8 +++ src/test/ui/pub/pub-restricted-non-path.rs | 15 +++++ src/test/ui/pub/pub-restricted-non-path.stderr | 8 +++ src/test/ui/pub/pub-restricted.rs | 37 +++++++++++++ src/test/ui/pub/pub-restricted.stderr | 47 ++++++++++++++++ 12 files changed, 205 insertions(+), 35 deletions(-) create mode 100644 src/test/ui/pub/pub-restricted-error-fn.rs create mode 100644 src/test/ui/pub/pub-restricted-error-fn.stderr create mode 100644 src/test/ui/pub/pub-restricted-error.rs create mode 100644 src/test/ui/pub/pub-restricted-error.stderr create mode 100644 src/test/ui/pub/pub-restricted-non-path.rs create mode 100644 src/test/ui/pub/pub-restricted-non-path.stderr create mode 100644 src/test/ui/pub/pub-restricted.rs create mode 100644 src/test/ui/pub/pub-restricted.stderr (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index df4ccc94c04..649e9059934 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4626,7 +4626,7 @@ impl<'a> Parser<'a> { let mut attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let vis = self.parse_visibility()?; + let vis = self.parse_visibility(false)?; let defaultness = self.parse_defaultness()?; let (name, node) = if self.eat_keyword(keywords::Type) { let name = self.parse_ident()?; @@ -4939,25 +4939,8 @@ impl<'a> Parser<'a> { |p| { let attrs = p.parse_outer_attributes()?; let lo = p.span.lo; - let mut vis = p.parse_visibility()?; - let ty_is_interpolated = - p.token.is_interpolated() || p.look_ahead(1, |t| t.is_interpolated()); - let mut ty = p.parse_ty()?; - - // Handle `pub(path) type`, in which `vis` will be `pub` and `ty` will be `(path)`. - if vis == Visibility::Public && !ty_is_interpolated && - p.token != token::Comma && p.token != token::CloseDelim(token::Paren) { - ty = if let TyKind::Paren(ref path_ty) = ty.node { - if let TyKind::Path(None, ref path) = path_ty.node { - vis = Visibility::Restricted { path: P(path.clone()), id: path_ty.id }; - Some(p.parse_ty()?) - } else { - None - } - } else { - None - }.unwrap_or(ty); - } + let vis = p.parse_visibility(true)?; + let ty = p.parse_ty()?; Ok(StructField { span: mk_sp(lo, p.span.hi), vis: vis, @@ -4996,18 +4979,25 @@ impl<'a> Parser<'a> { fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> { let attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let vis = self.parse_visibility()?; + let vis = self.parse_visibility(false)?; self.parse_single_struct_field(lo, vis, attrs) } - // Parse `pub`, `pub(crate)` and `pub(in path)` plus shortcuts - // `pub(self)` for `pub(in self)` and `pub(super)` for `pub(in super)`. - fn parse_visibility(&mut self) -> PResult<'a, Visibility> { + /// Parse `pub`, `pub(crate)` and `pub(in path)` plus shortcuts `pub(self)` for `pub(in self)` + /// and `pub(super)` for `pub(in super)`. If the following element can't be a tuple (i.e. it's + /// a function definition, it's not a tuple struct field) and the contents within the parens + /// isn't valid, emit a proper diagnostic. + fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> { if !self.eat_keyword(keywords::Pub) { return Ok(Visibility::Inherited) } if self.check(&token::OpenDelim(token::Paren)) { + let start_span = self.span; + // We don't `self.bump()` the `(` yet because this might be a struct definition where + // `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`. + // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so + // by the following tokens. if self.look_ahead(1, |t| t.is_keyword(keywords::Crate)) { // `pub(crate)` self.bump(); // `(` @@ -5032,6 +5022,28 @@ impl<'a> Parser<'a> { let vis = Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; self.expect(&token::CloseDelim(token::Paren))?; // `)` return Ok(vis) + } else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct + // `pub(something) fn ...` or `struct X { pub(something) y: Z }` + self.bump(); // `(` + let msg = "incorrect visibility restriction"; + let suggestion = r##"some possible visibility restrictions are: +`pub(crate)`: visible only on the current crate +`pub(super)`: visible only in the current module's parent +`pub(in path::to::module)`: visible only on the specified path"##; + let path = self.parse_path(PathStyle::Mod)?; + let path_span = self.prev_span; + let help_msg = format!("to make this visible only to module `{}`, add `in` before \ + the path:", + path); + self.expect(&token::CloseDelim(token::Paren))?; // `)` + let sp = Span { + lo: start_span.lo, + hi: self.prev_span.hi, + expn_id: start_span.expn_id, + }; + let mut err = self.span_fatal_help(sp, &msg, &suggestion); + err.span_suggestion(path_span, &help_msg, format!("in {}", path)); + err.emit(); // emit diagnostic, but continue with public visibility } } @@ -5508,7 +5520,7 @@ impl<'a> Parser<'a> { let lo = self.span.lo; - let visibility = self.parse_visibility()?; + let visibility = self.parse_visibility(false)?; if self.eat_keyword(keywords::Use) { // USE ITEM @@ -5787,7 +5799,7 @@ impl<'a> Parser<'a> { fn parse_foreign_item(&mut self) -> PResult<'a, Option> { let attrs = self.parse_outer_attributes()?; let lo = self.span.lo; - let visibility = self.parse_visibility()?; + let visibility = self.parse_visibility(false)?; if self.check_keyword(keywords::Static) { // FOREIGN STATIC ITEM diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs index 208f1a0e2ee..d17b604717e 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs @@ -10,7 +10,8 @@ mod foo { type T = (); - struct S1(pub(foo) (), pub(T), pub(crate) (), pub(((), T))); - struct S2(pub((foo)) ()); //~ ERROR expected `,`, found `(` - //~| ERROR expected one of `;` or `where`, found `(` + struct S1(pub(in foo) (), pub(T), pub(crate) (), pub(((), T))); + struct S2(pub((foo)) ()); + //~^ ERROR expected `,`, found `(` + //~| ERROR expected one of `;` or `where`, found `(` } diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs index 57769646e3b..166d5e27e8d 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs @@ -11,9 +11,10 @@ macro_rules! define_struct { ($t:ty) => { struct S1(pub $t); - struct S2(pub (foo) ()); - struct S3(pub $t ()); //~ ERROR expected `,`, found `(` - //~| ERROR expected one of `;` or `where`, found `(` + struct S2(pub (in foo) ()); + struct S3(pub $t ()); + //~^ ERROR expected `,`, found `(` + //~| ERROR expected one of `;` or `where`, found `(` } } diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs index db3358f7d50..edab175f4cd 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs @@ -11,9 +11,10 @@ macro_rules! define_struct { ($t:ty) => { struct S1(pub($t)); - struct S2(pub (foo) ()); - struct S3(pub($t) ()); //~ ERROR expected `,`, found `(` - //~| ERROR expected one of `;` or `where`, found `(` + struct S2(pub (in foo) ()); + struct S3(pub($t) ()); + //~^ ERROR expected `,`, found `(` + //~| ERROR expected one of `;` or `where`, found `(` } } diff --git a/src/test/ui/pub/pub-restricted-error-fn.rs b/src/test/ui/pub/pub-restricted-error-fn.rs new file mode 100644 index 00000000000..13514310371 --- /dev/null +++ b/src/test/ui/pub/pub-restricted-error-fn.rs @@ -0,0 +1,13 @@ +// Copyright 2017 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(pub_restricted)] + +pub(crate) () fn foo() {} diff --git a/src/test/ui/pub/pub-restricted-error-fn.stderr b/src/test/ui/pub/pub-restricted-error-fn.stderr new file mode 100644 index 00000000000..470e8331247 --- /dev/null +++ b/src/test/ui/pub/pub-restricted-error-fn.stderr @@ -0,0 +1,8 @@ +error: unmatched visibility `pub` + --> $DIR/pub-restricted-error-fn.rs:13:10 + | +13 | pub(crate) () fn foo() {} + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/pub/pub-restricted-error.rs b/src/test/ui/pub/pub-restricted-error.rs new file mode 100644 index 00000000000..99af031899a --- /dev/null +++ b/src/test/ui/pub/pub-restricted-error.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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(pub_restricted)] + +struct Bar(pub(())); + +struct Foo { + pub(crate) () foo: usize, +} + + diff --git a/src/test/ui/pub/pub-restricted-error.stderr b/src/test/ui/pub/pub-restricted-error.stderr new file mode 100644 index 00000000000..b8b4c80778d --- /dev/null +++ b/src/test/ui/pub/pub-restricted-error.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found `(` + --> $DIR/pub-restricted-error.rs:16:16 + | +16 | pub(crate) () foo: usize, + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/pub/pub-restricted-non-path.rs b/src/test/ui/pub/pub-restricted-non-path.rs new file mode 100644 index 00000000000..3f74285717a --- /dev/null +++ b/src/test/ui/pub/pub-restricted-non-path.rs @@ -0,0 +1,15 @@ +// Copyright 2017 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(pub_restricted)] + +pub (.) fn afn() {} + +fn main() {} diff --git a/src/test/ui/pub/pub-restricted-non-path.stderr b/src/test/ui/pub/pub-restricted-non-path.stderr new file mode 100644 index 00000000000..ebfccc4d720 --- /dev/null +++ b/src/test/ui/pub/pub-restricted-non-path.stderr @@ -0,0 +1,8 @@ +error: expected identifier, found `.` + --> $DIR/pub-restricted-non-path.rs:13:6 + | +13 | pub (.) fn afn() {} + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/pub/pub-restricted.rs b/src/test/ui/pub/pub-restricted.rs new file mode 100644 index 00000000000..48e487f71a7 --- /dev/null +++ b/src/test/ui/pub/pub-restricted.rs @@ -0,0 +1,37 @@ +// Copyright 2017 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(pub_restricted)] + +mod a {} + +pub (a) fn afn() {} +pub (b) fn bfn() {} +pub fn privfn() {} +mod x { + mod y { + pub (in x) fn foo() {} + pub (super) fn bar() {} + pub (crate) fn qux() {} + } +} + +mod y { + struct Foo { + pub (crate) c: usize, + pub (super) s: usize, + valid_private: usize, + pub (in y) valid_in_x: usize, + pub (a) invalid: usize, + pub (in x) non_parent_invalid: usize, + } +} + +fn main() {} \ No newline at end of file diff --git a/src/test/ui/pub/pub-restricted.stderr b/src/test/ui/pub/pub-restricted.stderr new file mode 100644 index 00000000000..5bc230e8da3 --- /dev/null +++ b/src/test/ui/pub/pub-restricted.stderr @@ -0,0 +1,47 @@ +error: incorrect visibility restriction + --> $DIR/pub-restricted.rs:15:5 + | +15 | pub (a) fn afn() {} + | ^^^ + | + = help: some possible visibility restrictions are: + `pub(crate)`: visible only on the current crate + `pub(super)`: visible only in the current module's parent + `pub(in path::to::module)`: visible only on the specified path +help: to make this visible only to module `a`, add `in` before the path: + | pub (in a) fn afn() {} + +error: incorrect visibility restriction + --> $DIR/pub-restricted.rs:16:5 + | +16 | pub (b) fn bfn() {} + | ^^^ + | + = help: some possible visibility restrictions are: + `pub(crate)`: visible only on the current crate + `pub(super)`: visible only in the current module's parent + `pub(in path::to::module)`: visible only on the specified path +help: to make this visible only to module `b`, add `in` before the path: + | pub (in b) fn bfn() {} + +error: incorrect visibility restriction + --> $DIR/pub-restricted.rs:32:13 + | +32 | pub (a) invalid: usize, + | ^^^ + | + = help: some possible visibility restrictions are: + `pub(crate)`: visible only on the current crate + `pub(super)`: visible only in the current module's parent + `pub(in path::to::module)`: visible only on the specified path +help: to make this visible only to module `a`, add `in` before the path: + | pub (in a) invalid: usize, + +error: visibilities can only be restricted to ancestor modules + --> $DIR/pub-restricted.rs:33:17 + | +33 | pub (in x) non_parent_invalid: usize, + | ^ + +error: aborting due to 4 previous errors + -- cgit 1.4.1-3-g733a5 From 57009caabd2a45a6efa4d36149feec39ab0a0658 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Fri, 24 Mar 2017 23:00:21 -0700 Subject: Identify missing item category in `impl`s ```rust struct S; impl S { pub hello_method(&self) { println!("Hello"); } } fn main() { S.hello_method(); } ``` ```rust error: can't qualify macro invocation with `pub` --> file.rs:3:4 | 3 | pub hello_method(&self) { | ^^^- - expected `!` here for a macro invocation | | | did you mean to write `fn` here for a method declaration? | = help: try adjusting the macro to put `pub` inside the invocation ``` --- src/libsyntax/parse/parser.rs | 62 ++++++++++++++++++++++------- src/test/ui/did_you_mean/issue-40006.rs | 21 ++++++++++ src/test/ui/did_you_mean/issue-40006.stderr | 12 ++++++ 3 files changed, 80 insertions(+), 15 deletions(-) create mode 100644 src/test/ui/did_you_mean/issue-40006.rs create mode 100644 src/test/ui/did_you_mean/issue-40006.stderr (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index df4ccc94c04..a19339f8cc1 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4660,25 +4660,30 @@ impl<'a> Parser<'a> { }) } - fn complain_if_pub_macro(&mut self, visa: &Visibility, span: Span) { - match *visa { - Visibility::Inherited => (), + fn complain_if_pub_macro(&mut self, vis: &Visibility, sp: Span) { + if let Err(mut err) = self.complain_if_pub_macro_diag(vis, sp) { + err.emit(); + } + } + + fn complain_if_pub_macro_diag(&mut self, vis: &Visibility, sp: Span) -> PResult<'a, ()> { + match *vis { + Visibility::Inherited => Ok(()), _ => { let is_macro_rules: bool = match self.token { token::Ident(sid) => sid.name == Symbol::intern("macro_rules"), _ => false, }; if is_macro_rules { - self.diagnostic().struct_span_err(span, "can't qualify macro_rules \ - invocation with `pub`") - .help("did you mean #[macro_export]?") - .emit(); + let mut err = self.diagnostic() + .struct_span_err(sp, "can't qualify macro_rules invocation with `pub`"); + err.help("did you mean #[macro_export]?"); + Err(err) } else { - self.diagnostic().struct_span_err(span, "can't qualify macro \ - invocation with `pub`") - .help("try adjusting the macro to put `pub` \ - inside the invocation") - .emit(); + let mut err = self.diagnostic() + .struct_span_err(sp, "can't qualify macro invocation with `pub`"); + err.help("try adjusting the macro to put `pub` inside the invocation"); + Err(err) } } } @@ -4689,14 +4694,41 @@ impl<'a> Parser<'a> { -> PResult<'a, (Ident, Vec, ast::ImplItemKind)> { // code copied from parse_macro_use_or_failure... abstraction! if self.token.is_path_start() { - // method macro. + // Method macro. let prev_span = self.prev_span; - self.complain_if_pub_macro(&vis, prev_span); + // Before complaining about trying to set a macro as `pub`, + // check if `!` comes after the path. + let err = self.complain_if_pub_macro_diag(&vis, prev_span); let lo = self.span.lo; let pth = self.parse_path(PathStyle::Mod)?; - self.expect(&token::Not)?; + let bang_err = self.expect(&token::Not); + if let Err(mut err) = err { + if let Err(mut bang_err) = bang_err { + // Given this code `pub path(`, it seems like this is not setting the + // visibility of a macro invocation, but rather a mistyped method declaration. + // Keep the macro diagnostic, but also provide a hint that `fn` might be + // missing. Don't complain about the missing `!` as a separate diagnostic, add + // label in the appropriate place as part of one unified diagnostic. + // + // x | pub path(&self) { + // | ^^^- - expected `!` here for a macro invocation + // | | + // | did you mean to write `fn` here for a method declaration? + + bang_err.cancel(); + err.span_label(self.span, &"expected `!` here for a macro invocation"); + // pub path( + // ^^ `sp` below will point to this + let sp = mk_sp(prev_span.hi, self.prev_span.lo); + err.span_label(sp, + &"did you mean to write `fn` here for a method declaration?"); + } + return Err(err); + } else if let Err(bang_err) = bang_err { + return Err(bang_err); + } // eat a matched-delimiter token tree: let (delim, tts) = self.expect_delimited_token_tree()?; diff --git a/src/test/ui/did_you_mean/issue-40006.rs b/src/test/ui/did_you_mean/issue-40006.rs new file mode 100644 index 00000000000..cf75929bae2 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40006.rs @@ -0,0 +1,21 @@ +// Copyright 2017 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. + +struct S; + +impl S { + pub hello_method(&self) { + println!("Hello"); + } +} + +fn main() { + S.hello_method(); +} diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr new file mode 100644 index 00000000000..93a0c58f91a --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -0,0 +1,12 @@ +error: can't qualify macro invocation with `pub` + --> $DIR/issue-40006.rs:14:5 + | +14 | pub hello_method(&self) { + | ^^^- - expected `!` here for a macro invocation + | | + | did you mean to write `fn` here for a method declaration? + | + = help: try adjusting the macro to put `pub` inside the invocation + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 03eca713816ee00ecacde27cc655dc199c6bff40 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Fri, 24 Mar 2017 19:14:58 -0700 Subject: Point at last valid token on failed `expect_one_of` ```rust error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` --> $DIR/token-error-correct-3.rs:29:9 | 25 | foo() | - expected one of `.`, `;`, `?`, `}`, or an operator after this ... 29 | } else { | ^ unexpected token ``` --- src/libsyntax/parse/parser.rs | 28 ++++++++++++------------ src/test/compile-fail/issue-10636-2.rs | 2 ++ src/test/compile-fail/macro-incomplete-parse.rs | 2 ++ src/test/parse-fail/bounds-obj-parens.rs | 4 +++- src/test/parse-fail/match-refactor-to-expr.rs | 4 +++- src/test/parse-fail/trailing-plus-in-bounds.rs | 4 +++- src/test/ui/resolve/token-error-correct-3.stderr | 9 ++++++-- src/test/ui/resolve/token-error-correct.stderr | 4 +++- 8 files changed, 37 insertions(+), 20 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index df4ccc94c04..6379015055b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -548,20 +548,20 @@ impl<'a> Parser<'a> { expected.dedup(); let expect = tokens_to_string(&expected[..]); let actual = self.this_token_to_string(); - Err(self.fatal( - &(if expected.len() > 1 { - (format!("expected one of {}, found `{}`", - expect, - actual)) - } else if expected.is_empty() { - (format!("unexpected token: `{}`", - actual)) - } else { - (format!("expected {}, found `{}`", - expect, - actual)) - })[..] - )) + let (msg_exp, label_exp) = if expected.len() > 1 { + (format!("expected one of {}, found `{}`", expect, actual), + format!("expected one of {} after this", expect)) + } else if expected.is_empty() { + (format!("unexpected token: `{}`", actual), + "unexpected token after this".to_string()) + } else { + (format!("expected {}, found `{}`", expect, actual), + format!("expected {} after this", expect)) + }; + let mut err = self.fatal(&msg_exp); + err.span_label(self.prev_span, &label_exp); + err.span_label(self.span, &"unexpected token"); + Err(err) } } diff --git a/src/test/compile-fail/issue-10636-2.rs b/src/test/compile-fail/issue-10636-2.rs index beaf9e5059f..93759123618 100644 --- a/src/test/compile-fail/issue-10636-2.rs +++ b/src/test/compile-fail/issue-10636-2.rs @@ -14,5 +14,7 @@ pub fn trace_option(option: Option) { option.map(|some| 42; //~ NOTE: unclosed delimiter //~^ ERROR: expected one of + //~| NOTE: expected one of + //~| NOTE: unexpected token } //~ ERROR: incorrect close delimiter //~^ ERROR: expected expression, found `)` diff --git a/src/test/compile-fail/macro-incomplete-parse.rs b/src/test/compile-fail/macro-incomplete-parse.rs index c2ac99d1f6a..682664df981 100644 --- a/src/test/compile-fail/macro-incomplete-parse.rs +++ b/src/test/compile-fail/macro-incomplete-parse.rs @@ -20,6 +20,8 @@ macro_rules! ignored_item { macro_rules! ignored_expr { () => ( 1, //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + //~^ NOTE expected one of `.`, `;`, `?`, `}`, or an operator after this + //~| NOTE unexpected token 2 ) } diff --git a/src/test/parse-fail/bounds-obj-parens.rs b/src/test/parse-fail/bounds-obj-parens.rs index ad59d4a52d7..02c119cf727 100644 --- a/src/test/parse-fail/bounds-obj-parens.rs +++ b/src/test/parse-fail/bounds-obj-parens.rs @@ -12,4 +12,6 @@ type A = Box<(Fn(D::Error) -> E) + 'static + Send + Sync>; // OK (but see #39318) -FAIL //~ ERROR +FAIL +//~^ ERROR +//~| ERROR diff --git a/src/test/parse-fail/match-refactor-to-expr.rs b/src/test/parse-fail/match-refactor-to-expr.rs index 37b66601e70..7bb1c40118a 100644 --- a/src/test/parse-fail/match-refactor-to-expr.rs +++ b/src/test/parse-fail/match-refactor-to-expr.rs @@ -14,7 +14,9 @@ fn main() { let foo = match //~ NOTE did you mean to remove this `match` keyword? Some(4).unwrap_or_else(5) - ; //~ ERROR expected one of `.`, `?`, `{`, or an operator, found `;` + //~^ NOTE expected one of `.`, `?`, `{`, or an operator after this + ; //~ NOTE unexpected token + //~^ ERROR expected one of `.`, `?`, `{`, or an operator, found `;` println!("{}", foo) } diff --git a/src/test/parse-fail/trailing-plus-in-bounds.rs b/src/test/parse-fail/trailing-plus-in-bounds.rs index 4a2e6d5bdcd..2bb2c97790c 100644 --- a/src/test/parse-fail/trailing-plus-in-bounds.rs +++ b/src/test/parse-fail/trailing-plus-in-bounds.rs @@ -16,4 +16,6 @@ fn main() { let x: Box = box 3 as Box; // Trailing `+` is OK } -FAIL //~ ERROR +FAIL +//~^ ERROR +//~| ERROR diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr index 56e36889575..2e0edf0c4b8 100644 --- a/src/test/ui/resolve/token-error-correct-3.stderr +++ b/src/test/ui/resolve/token-error-correct-3.stderr @@ -14,13 +14,18 @@ error: expected one of `,`, `.`, `?`, or an operator, found `;` --> $DIR/token-error-correct-3.rs:23:35 | 23 | callback(path.as_ref(); //~ NOTE: unclosed delimiter - | ^ + | -^ unexpected token + | | + | expected one of `,`, `.`, `?`, or an operator after this error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` --> $DIR/token-error-correct-3.rs:29:9 | +25 | fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types + | - expected one of `.`, `;`, `?`, `}`, or an operator after this +... 29 | } else { //~ ERROR: incorrect close delimiter: `}` - | ^ + | ^ unexpected token error[E0425]: cannot find function `is_directory` in this scope --> $DIR/token-error-correct-3.rs:21:13 diff --git a/src/test/ui/resolve/token-error-correct.stderr b/src/test/ui/resolve/token-error-correct.stderr index 248a923efaf..36f298a456a 100644 --- a/src/test/ui/resolve/token-error-correct.stderr +++ b/src/test/ui/resolve/token-error-correct.stderr @@ -32,7 +32,9 @@ error: expected one of `)`, `,`, `.`, `<`, `?`, `break`, `continue`, `false`, `f --> $DIR/token-error-correct.rs:14:13 | 14 | foo(bar(; - | ^ + | -^ unexpected token + | | + | expected one of `)`, `,`, `.`, `<`, `?`, `break`, `continue`, `false`, `for`, `if`, `loop`, `match`, `move`, `return`, `true`, `unsafe`, `while`, or an operator after this error: expected expression, found `)` --> $DIR/token-error-correct.rs:23:1 -- cgit 1.4.1-3-g733a5 From 78ae8feebbf9a2c70d42780d0c646cbbc1f2cdbc Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sat, 25 Mar 2017 15:36:59 -0700 Subject: Improve wording and spans for unexpected token * Point at where the token was expected instead of the last token successfuly parsed. * Only show `unexpected token` if the next char and the unexpected token don't have the same span. * Change some cfail and pfail tests to ui test. * Don't show all possible tokens in span label if they are more than 6. --- src/libsyntax/parse/parser.rs | 25 +++++++++++---- src/libsyntax_pos/lib.rs | 6 ++++ src/test/compile-fail/issue-10636-2.rs | 20 ------------ src/test/compile-fail/macro-incomplete-parse.rs | 40 ------------------------ src/test/parse-fail/bounds-obj-parens.rs | 17 ---------- src/test/parse-fail/match-refactor-to-expr.rs | 2 +- src/test/parse-fail/trailing-plus-in-bounds.rs | 21 ------------- src/test/ui/resolve/token-error-correct-3.stderr | 6 ++-- src/test/ui/resolve/token-error-correct.stderr | 4 +-- src/test/ui/token/bounds-obj-parens.rs | 17 ++++++++++ src/test/ui/token/bounds-obj-parens.stderr | 7 +++++ src/test/ui/token/issue-10636-2.rs | 20 ++++++++++++ src/test/ui/token/issue-10636-2.stderr | 27 ++++++++++++++++ src/test/ui/token/macro-incomplete-parse.rs | 40 ++++++++++++++++++++++++ src/test/ui/token/macro-incomplete-parse.stderr | 31 ++++++++++++++++++ src/test/ui/token/trailing-plus-in-bounds.rs | 21 +++++++++++++ src/test/ui/token/trailing-plus-in-bounds.stderr | 7 +++++ 17 files changed, 199 insertions(+), 112 deletions(-) delete mode 100644 src/test/compile-fail/issue-10636-2.rs delete mode 100644 src/test/compile-fail/macro-incomplete-parse.rs delete mode 100644 src/test/parse-fail/bounds-obj-parens.rs delete mode 100644 src/test/parse-fail/trailing-plus-in-bounds.rs create mode 100644 src/test/ui/token/bounds-obj-parens.rs create mode 100644 src/test/ui/token/bounds-obj-parens.stderr create mode 100644 src/test/ui/token/issue-10636-2.rs create mode 100644 src/test/ui/token/issue-10636-2.stderr create mode 100644 src/test/ui/token/macro-incomplete-parse.rs create mode 100644 src/test/ui/token/macro-incomplete-parse.stderr create mode 100644 src/test/ui/token/trailing-plus-in-bounds.rs create mode 100644 src/test/ui/token/trailing-plus-in-bounds.stderr (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6379015055b..4076368c180 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -548,19 +548,32 @@ impl<'a> Parser<'a> { expected.dedup(); let expect = tokens_to_string(&expected[..]); let actual = self.this_token_to_string(); - let (msg_exp, label_exp) = if expected.len() > 1 { + let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { + let short_expect = if expected.len() > 6 { + format!("{} possible tokens", expected.len()) + } else { + expect.clone() + }; (format!("expected one of {}, found `{}`", expect, actual), - format!("expected one of {} after this", expect)) + (self.prev_span.next_point(), format!("expected one of {} here", short_expect))) } else if expected.is_empty() { (format!("unexpected token: `{}`", actual), - "unexpected token after this".to_string()) + (self.prev_span, "unexpected token after this".to_string())) } else { (format!("expected {}, found `{}`", expect, actual), - format!("expected {} after this", expect)) + (self.prev_span.next_point(), format!("expected {} here", expect))) }; let mut err = self.fatal(&msg_exp); - err.span_label(self.prev_span, &label_exp); - err.span_label(self.span, &"unexpected token"); + let sp = if self.token == token::Token::Eof { + // This is EOF, don't want to point at the following char, but rather the last token + self.prev_span + } else { + label_sp + }; + err.span_label(sp, &label_exp); + if label_sp != self.span { + err.span_label(self.span, &"unexpected token"); + } Err(err) } } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 3808923e772..07494ff904e 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -79,6 +79,12 @@ impl Span { Span { lo: BytePos(lo), hi: self.hi, expn_id: self.expn_id} } + /// Returns a new span representing the next character after the end-point of this span + pub fn next_point(self) -> Span { + let lo = BytePos(cmp::max(self.hi.0, self.lo.0 + 1)); + Span { lo: lo, hi: lo, expn_id: self.expn_id} + } + /// Returns `self` if `self` is not the dummy span, and `other` otherwise. pub fn substitute_dummy(self, other: Span) -> Span { if self.source_equal(&DUMMY_SP) { other } else { self } diff --git a/src/test/compile-fail/issue-10636-2.rs b/src/test/compile-fail/issue-10636-2.rs deleted file mode 100644 index 93759123618..00000000000 --- a/src/test/compile-fail/issue-10636-2.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2013-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. - -// FIXME(31528) we emit a bunch of silly errors here due to continuing past the -// first one. This would be easy-ish to address by better recovery in tokenisation. - -pub fn trace_option(option: Option) { - option.map(|some| 42; //~ NOTE: unclosed delimiter - //~^ ERROR: expected one of - //~| NOTE: expected one of - //~| NOTE: unexpected token -} //~ ERROR: incorrect close delimiter -//~^ ERROR: expected expression, found `)` diff --git a/src/test/compile-fail/macro-incomplete-parse.rs b/src/test/compile-fail/macro-incomplete-parse.rs deleted file mode 100644 index 682664df981..00000000000 --- a/src/test/compile-fail/macro-incomplete-parse.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2013 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 continue-parse-after-error - -macro_rules! ignored_item { - () => { - fn foo() {} - fn bar() {} - , //~ ERROR macro expansion ignores token `,` - } -} - -macro_rules! ignored_expr { - () => ( 1, //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `,` - //~^ NOTE expected one of `.`, `;`, `?`, `}`, or an operator after this - //~| NOTE unexpected token - 2 ) -} - -macro_rules! ignored_pat { - () => ( 1, 2 ) //~ ERROR macro expansion ignores token `,` -} - -ignored_item!(); //~ NOTE caused by the macro expansion here - -fn main() { - ignored_expr!(); - match 1 { - ignored_pat!() => (), //~ NOTE caused by the macro expansion here - _ => (), - } -} diff --git a/src/test/parse-fail/bounds-obj-parens.rs b/src/test/parse-fail/bounds-obj-parens.rs deleted file mode 100644 index 02c119cf727..00000000000 --- a/src/test/parse-fail/bounds-obj-parens.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017 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 - -type A = Box<(Fn(D::Error) -> E) + 'static + Send + Sync>; // OK (but see #39318) - -FAIL -//~^ ERROR -//~| ERROR diff --git a/src/test/parse-fail/match-refactor-to-expr.rs b/src/test/parse-fail/match-refactor-to-expr.rs index 7bb1c40118a..e2fee1d1895 100644 --- a/src/test/parse-fail/match-refactor-to-expr.rs +++ b/src/test/parse-fail/match-refactor-to-expr.rs @@ -14,7 +14,7 @@ fn main() { let foo = match //~ NOTE did you mean to remove this `match` keyword? Some(4).unwrap_or_else(5) - //~^ NOTE expected one of `.`, `?`, `{`, or an operator after this + //~^ NOTE expected one of `.`, `?`, `{`, or an operator here ; //~ NOTE unexpected token //~^ ERROR expected one of `.`, `?`, `{`, or an operator, found `;` diff --git a/src/test/parse-fail/trailing-plus-in-bounds.rs b/src/test/parse-fail/trailing-plus-in-bounds.rs deleted file mode 100644 index 2bb2c97790c..00000000000 --- a/src/test/parse-fail/trailing-plus-in-bounds.rs +++ /dev/null @@ -1,21 +0,0 @@ -// 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 -Z continue-parse-after-error - -use std::fmt::Debug; - -fn main() { - let x: Box = box 3 as Box; // Trailing `+` is OK -} - -FAIL -//~^ ERROR -//~| ERROR diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr index 2e0edf0c4b8..bf7db67e728 100644 --- a/src/test/ui/resolve/token-error-correct-3.stderr +++ b/src/test/ui/resolve/token-error-correct-3.stderr @@ -14,15 +14,13 @@ error: expected one of `,`, `.`, `?`, or an operator, found `;` --> $DIR/token-error-correct-3.rs:23:35 | 23 | callback(path.as_ref(); //~ NOTE: unclosed delimiter - | -^ unexpected token - | | - | expected one of `,`, `.`, `?`, or an operator after this + | ^ expected one of `,`, `.`, `?`, or an operator here error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` --> $DIR/token-error-correct-3.rs:29:9 | 25 | fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types - | - expected one of `.`, `;`, `?`, `}`, or an operator after this + | - expected one of `.`, `;`, `?`, `}`, or an operator here ... 29 | } else { //~ ERROR: incorrect close delimiter: `}` | ^ unexpected token diff --git a/src/test/ui/resolve/token-error-correct.stderr b/src/test/ui/resolve/token-error-correct.stderr index 36f298a456a..226fa6469bc 100644 --- a/src/test/ui/resolve/token-error-correct.stderr +++ b/src/test/ui/resolve/token-error-correct.stderr @@ -32,9 +32,7 @@ error: expected one of `)`, `,`, `.`, `<`, `?`, `break`, `continue`, `false`, `f --> $DIR/token-error-correct.rs:14:13 | 14 | foo(bar(; - | -^ unexpected token - | | - | expected one of `)`, `,`, `.`, `<`, `?`, `break`, `continue`, `false`, `for`, `if`, `loop`, `match`, `move`, `return`, `true`, `unsafe`, `while`, or an operator after this + | ^ expected one of 18 possible tokens here error: expected expression, found `)` --> $DIR/token-error-correct.rs:23:1 diff --git a/src/test/ui/token/bounds-obj-parens.rs b/src/test/ui/token/bounds-obj-parens.rs new file mode 100644 index 00000000000..02c119cf727 --- /dev/null +++ b/src/test/ui/token/bounds-obj-parens.rs @@ -0,0 +1,17 @@ +// Copyright 2017 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 + +type A = Box<(Fn(D::Error) -> E) + 'static + Send + Sync>; // OK (but see #39318) + +FAIL +//~^ ERROR +//~| ERROR diff --git a/src/test/ui/token/bounds-obj-parens.stderr b/src/test/ui/token/bounds-obj-parens.stderr new file mode 100644 index 00000000000..ebee363f278 --- /dev/null +++ b/src/test/ui/token/bounds-obj-parens.stderr @@ -0,0 +1,7 @@ +error: expected one of `!` or `::`, found `` + --> $DIR/bounds-obj-parens.rs:15:1 + | +15 | FAIL + | ^^^^ expected one of `!` or `::` here + +error: aborting due to previous error diff --git a/src/test/ui/token/issue-10636-2.rs b/src/test/ui/token/issue-10636-2.rs new file mode 100644 index 00000000000..93759123618 --- /dev/null +++ b/src/test/ui/token/issue-10636-2.rs @@ -0,0 +1,20 @@ +// Copyright 2013-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. + +// FIXME(31528) we emit a bunch of silly errors here due to continuing past the +// first one. This would be easy-ish to address by better recovery in tokenisation. + +pub fn trace_option(option: Option) { + option.map(|some| 42; //~ NOTE: unclosed delimiter + //~^ ERROR: expected one of + //~| NOTE: expected one of + //~| NOTE: unexpected token +} //~ ERROR: incorrect close delimiter +//~^ ERROR: expected expression, found `)` diff --git a/src/test/ui/token/issue-10636-2.stderr b/src/test/ui/token/issue-10636-2.stderr new file mode 100644 index 00000000000..183ad30c4ef --- /dev/null +++ b/src/test/ui/token/issue-10636-2.stderr @@ -0,0 +1,27 @@ +error: incorrect close delimiter: `}` + --> $DIR/issue-10636-2.rs:19:1 + | +19 | } //~ ERROR: incorrect close delimiter + | ^ + | +note: unclosed delimiter + --> $DIR/issue-10636-2.rs:15:15 + | +15 | option.map(|some| 42; //~ NOTE: unclosed delimiter + | ^ + +error: expected one of `,`, `.`, `?`, or an operator, found `;` + --> $DIR/issue-10636-2.rs:15:25 + | +15 | option.map(|some| 42; //~ NOTE: unclosed delimiter + | ^ expected one of `,`, `.`, `?`, or an operator here + +error: expected expression, found `)` + --> $DIR/issue-10636-2.rs:19:1 + | +19 | } //~ ERROR: incorrect close delimiter + | ^ + +error: main function not found + +error: aborting due to 4 previous errors diff --git a/src/test/ui/token/macro-incomplete-parse.rs b/src/test/ui/token/macro-incomplete-parse.rs new file mode 100644 index 00000000000..47374fc3c60 --- /dev/null +++ b/src/test/ui/token/macro-incomplete-parse.rs @@ -0,0 +1,40 @@ +// Copyright 2013 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 continue-parse-after-error + +macro_rules! ignored_item { + () => { + fn foo() {} + fn bar() {} + , //~ ERROR macro expansion ignores token `,` + } +} + +macro_rules! ignored_expr { + () => ( 1, //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + //~^ NOTE expected one of `.`, `;`, `?`, `}`, or an operator here + //~| NOTE unexpected token + 2 ) +} + +macro_rules! ignored_pat { + () => ( 1, 2 ) //~ ERROR macro expansion ignores token `,` +} + +ignored_item!(); //~ NOTE caused by the macro expansion here + +fn main() { + ignored_expr!(); + match 1 { + ignored_pat!() => (), //~ NOTE caused by the macro expansion here + _ => (), + } +} diff --git a/src/test/ui/token/macro-incomplete-parse.stderr b/src/test/ui/token/macro-incomplete-parse.stderr new file mode 100644 index 00000000000..bea00a6444c --- /dev/null +++ b/src/test/ui/token/macro-incomplete-parse.stderr @@ -0,0 +1,31 @@ +error: macro expansion ignores token `,` and any following + --> $DIR/macro-incomplete-parse.rs:17:9 + | +17 | , //~ ERROR macro expansion ignores token `,` + | ^ + | +note: caused by the macro expansion here; the usage of `ignored_item!` is likely invalid in item context + --> $DIR/macro-incomplete-parse.rs:32:1 + | +32 | ignored_item!(); //~ NOTE caused by the macro expansion here + | ^^^^^^^^^^^^^^^^ + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + --> $DIR/macro-incomplete-parse.rs:22:14 + | +22 | () => ( 1, //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `,` + | ^ expected one of `.`, `;`, `?`, `}`, or an operator here + +error: macro expansion ignores token `,` and any following + --> $DIR/macro-incomplete-parse.rs:29:14 + | +29 | () => ( 1, 2 ) //~ ERROR macro expansion ignores token `,` + | ^ + | +note: caused by the macro expansion here; the usage of `ignored_pat!` is likely invalid in pattern context + --> $DIR/macro-incomplete-parse.rs:37:9 + | +37 | ignored_pat!() => (), //~ NOTE caused by the macro expansion here + | ^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors diff --git a/src/test/ui/token/trailing-plus-in-bounds.rs b/src/test/ui/token/trailing-plus-in-bounds.rs new file mode 100644 index 00000000000..2bb2c97790c --- /dev/null +++ b/src/test/ui/token/trailing-plus-in-bounds.rs @@ -0,0 +1,21 @@ +// 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 -Z continue-parse-after-error + +use std::fmt::Debug; + +fn main() { + let x: Box = box 3 as Box; // Trailing `+` is OK +} + +FAIL +//~^ ERROR +//~| ERROR diff --git a/src/test/ui/token/trailing-plus-in-bounds.stderr b/src/test/ui/token/trailing-plus-in-bounds.stderr new file mode 100644 index 00000000000..74caf8f5c2b --- /dev/null +++ b/src/test/ui/token/trailing-plus-in-bounds.stderr @@ -0,0 +1,7 @@ +error: expected one of `!` or `::`, found `` + --> ../../src/test/ui/token/trailing-plus-in-bounds.rs:19:1 + | +19 | FAIL + | ^^^^ expected one of `!` or `::` here + +error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From eb447f4ef436f0c6211a13de1e6150a09228a9c6 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 24 Mar 2017 09:31:26 +0100 Subject: Fix various useless derefs and slicings --- src/bootstrap/check.rs | 2 +- src/grammar/verify.rs | 6 +++--- src/libcollections/linked_list.rs | 2 +- src/libgraphviz/lib.rs | 6 +++--- src/librustc/ich/fingerprint.rs | 4 ++-- src/librustc/lint/context.rs | 5 ++--- src/librustc/middle/stability.rs | 2 +- src/librustc_borrowck/borrowck/fragments.rs | 24 ++++++++++++------------ src/librustc_borrowck/borrowck/mod.rs | 2 +- src/librustc_borrowck/graphviz.rs | 2 +- src/librustc_const_eval/_match.rs | 4 ++-- src/librustc_const_eval/check_match.rs | 2 +- src/librustc_data_structures/accumulate_vec.rs | 8 ++++---- src/librustc_data_structures/base_n.rs | 2 +- src/librustc_data_structures/blake2b.rs | 2 +- src/librustc_data_structures/indexed_set.rs | 8 ++++---- src/librustc_driver/lib.rs | 10 +++++----- src/librustc_driver/pretty.rs | 6 +++--- src/librustc_driver/test.rs | 2 +- src/librustc_incremental/persist/file_format.rs | 4 ++-- src/librustc_lint/bad_style.rs | 2 +- src/librustc_lint/builtin.rs | 2 +- src/librustc_lint/unused.rs | 2 +- src/librustc_llvm/build.rs | 4 ++-- src/librustc_metadata/creader.rs | 2 +- src/librustc_metadata/encoder.rs | 4 ++-- src/librustc_metadata/locator.rs | 6 +++--- src/librustc_plugin/load.rs | 6 +++--- src/librustc_save_analysis/csv_dumper.rs | 2 +- src/librustc_trans/abi.rs | 2 +- src/librustc_trans/adt.rs | 8 ++++---- src/librustc_trans/asm.rs | 4 ++-- src/librustc_trans/back/archive.rs | 4 ++-- src/librustc_trans/back/link.rs | 14 +++++++------- src/librustc_trans/back/lto.rs | 4 ++-- src/librustc_trans/back/rpath.rs | 14 +++++++------- src/librustc_trans/back/symbol_export.rs | 4 ++-- src/librustc_trans/back/symbol_names.rs | 2 +- src/librustc_trans/back/write.rs | 12 ++++++------ src/librustc_trans/base.rs | 12 ++++++------ src/librustc_trans/builder.rs | 6 +++--- src/librustdoc/html/render.rs | 4 ++-- src/libsyntax/ext/tt/macro_rules.rs | 2 +- src/libsyntax/feature_gate.rs | 9 ++++----- src/libsyntax/parse/parser.rs | 6 +++--- src/libsyntax/test.rs | 2 +- 46 files changed, 120 insertions(+), 122 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 40cdb9242df..f8f641060c4 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -586,7 +586,7 @@ fn android_copy_libs(build: &Build, compiler: &Compiler, target: &str) { .arg(ADB_TEST_DIR)); let target_dir = format!("{}/{}", ADB_TEST_DIR, target); - build.run(Command::new("adb").args(&["shell", "mkdir", &target_dir[..]])); + build.run(Command::new("adb").args(&["shell", "mkdir", &target_dir])); for f in t!(build.sysroot_libdir(compiler, target).read_dir()) { let f = t!(f); diff --git a/src/grammar/verify.rs b/src/grammar/verify.rs index 919fc98e438..bd28a63c5f4 100644 --- a/src/grammar/verify.rs +++ b/src/grammar/verify.rs @@ -196,7 +196,7 @@ fn parse_antlr_token(s: &str, tokens: &HashMap, surrogate_ let toknum = &s[content_end + 3 .. toknum_end]; let not_found = format!("didn't find token {:?} in the map", toknum); - let proto_tok = tokens.get(toknum).expect(¬_found[..]); + let proto_tok = tokens.get(toknum).expect(¬_found); let nm = Symbol::intern(content); @@ -304,14 +304,14 @@ fn main() { let mut token_file = File::open(&Path::new(&args.next().unwrap())).unwrap(); let mut token_list = String::new(); token_file.read_to_string(&mut token_list).unwrap(); - let token_map = parse_token_list(&token_list[..]); + let token_map = parse_token_list(&token_list); let stdin = std::io::stdin(); let lock = stdin.lock(); let lines = lock.lines(); let antlr_tokens = lines.map(|l| parse_antlr_token(l.unwrap().trim(), &token_map, - &surrogate_pairs_pos[..], + &surrogate_pairs_pos, has_bom)); for antlr_tok in antlr_tokens { diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index f58c87b801f..8f0488f6936 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -1376,7 +1376,7 @@ mod tests { thread::spawn(move || { check_links(&n); let a: &[_] = &[&1, &2, &3]; - assert_eq!(a, &n.iter().collect::>()[..]); + assert_eq!(a, &*n.iter().collect::>()); }) .join() .ok() diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 8e587ad211d..1b2c7775185 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -554,7 +554,7 @@ impl<'a> LabelText<'a> { pub fn to_dot_string(&self) -> String { match self { &LabelStr(ref s) => format!("\"{}\"", s.escape_default()), - &EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(&s[..])), + &EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(&s)), &HtmlStr(ref s) => format!("<{}>", s), } } @@ -587,7 +587,7 @@ impl<'a> LabelText<'a> { let mut prefix = self.pre_escaped_content().into_owned(); let suffix = suffix.pre_escaped_content(); prefix.push_str(r"\n\n"); - prefix.push_str(&suffix[..]); + prefix.push_str(&suffix); EscStr(prefix.into_cow()) } } @@ -878,7 +878,7 @@ mod tests { type Node = Node; type Edge = &'a Edge; fn graph_id(&'a self) -> Id<'a> { - Id::new(&self.name[..]).unwrap() + Id::new(self.name).unwrap() } fn node_id(&'a self, n: &Node) -> Id<'a> { id_name(n) diff --git a/src/librustc/ich/fingerprint.rs b/src/librustc/ich/fingerprint.rs index d296d8293fb..e760f7efc93 100644 --- a/src/librustc/ich/fingerprint.rs +++ b/src/librustc/ich/fingerprint.rs @@ -55,7 +55,7 @@ impl Fingerprint { impl Encodable for Fingerprint { #[inline] fn encode(&self, s: &mut S) -> Result<(), S::Error> { - for &byte in &self.0[..] { + for &byte in &self.0 { s.emit_u8(byte)?; } Ok(()) @@ -66,7 +66,7 @@ impl Decodable for Fingerprint { #[inline] fn decode(d: &mut D) -> Result { let mut result = Fingerprint([0u8; FINGERPRINT_LENGTH]); - for byte in &mut result.0[..] { + for byte in &mut result.0 { *byte = d.read_u8()?; } Ok(result) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index d35f965e2ff..20bf241a999 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -40,7 +40,6 @@ use std::cmp; use std::default::Default as StdDefault; use std::mem; use std::fmt; -use std::ops::Deref; use syntax::attr; use syntax::ast; use syntax::symbol::Symbol; @@ -485,7 +484,7 @@ pub fn raw_struct_lint<'a, S>(sess: &'a Session, Allow => bug!("earlier conditional return should handle Allow case") }; let hyphen_case_lint_name = name.replace("_", "-"); - if lint_flag_val.as_str().deref() == name { + if lint_flag_val.as_str() == name { err.note(&format!("requested on the command line with `{} {}`", flag, hyphen_case_lint_name)); } else { @@ -496,7 +495,7 @@ pub fn raw_struct_lint<'a, S>(sess: &'a Session, }, Node(lint_attr_name, src) => { def = Some(src); - if lint_attr_name.as_str().deref() != name { + if lint_attr_name.as_str() != name { let level_str = level.as_str(); err.note(&format!("#[{}({})] implied by #[{}({})]", level_str, name, level_str, lint_attr_name)); diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 4115b4669f4..4354ed6817a 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -536,7 +536,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if !self.stability.borrow().active_features.contains(feature) { let msg = match *reason { Some(ref r) => format!("use of unstable library feature '{}': {}", - &feature.as_str(), &r), + feature.as_str(), &r), None => format!("use of unstable library feature '{}'", &feature) }; emit_feature_err(&self.sess.parse_sess, &feature.as_str(), span, diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index c0f681680a9..b728d4d5345 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -267,11 +267,11 @@ pub fn fixup_fragment_sets<'a, 'tcx>(this: &MoveData<'tcx>, tcx: TyCtxt<'a, 'tcx // First, filter out duplicates moved.sort(); moved.dedup(); - debug!("fragments 1 moved: {:?}", path_lps(&moved[..])); + debug!("fragments 1 moved: {:?}", path_lps(&moved)); assigned.sort(); assigned.dedup(); - debug!("fragments 1 assigned: {:?}", path_lps(&assigned[..])); + debug!("fragments 1 assigned: {:?}", path_lps(&assigned)); // Second, build parents from the moved and assigned. for m in &moved { @@ -291,14 +291,14 @@ pub fn fixup_fragment_sets<'a, 'tcx>(this: &MoveData<'tcx>, tcx: TyCtxt<'a, 'tcx parents.sort(); parents.dedup(); - debug!("fragments 2 parents: {:?}", path_lps(&parents[..])); + debug!("fragments 2 parents: {:?}", path_lps(&parents)); // Third, filter the moved and assigned fragments down to just the non-parents - moved.retain(|f| non_member(*f, &parents[..])); - debug!("fragments 3 moved: {:?}", path_lps(&moved[..])); + moved.retain(|f| non_member(*f, &parents)); + debug!("fragments 3 moved: {:?}", path_lps(&moved)); - assigned.retain(|f| non_member(*f, &parents[..])); - debug!("fragments 3 assigned: {:?}", path_lps(&assigned[..])); + assigned.retain(|f| non_member(*f, &parents)); + debug!("fragments 3 assigned: {:?}", path_lps(&assigned)); // Fourth, build the leftover from the moved, assigned, and parents. for m in &moved { @@ -316,16 +316,16 @@ pub fn fixup_fragment_sets<'a, 'tcx>(this: &MoveData<'tcx>, tcx: TyCtxt<'a, 'tcx unmoved.sort(); unmoved.dedup(); - debug!("fragments 4 unmoved: {:?}", frag_lps(&unmoved[..])); + debug!("fragments 4 unmoved: {:?}", frag_lps(&unmoved)); // Fifth, filter the leftover fragments down to its core. unmoved.retain(|f| match *f { AllButOneFrom(_) => true, - Just(mpi) => non_member(mpi, &parents[..]) && - non_member(mpi, &moved[..]) && - non_member(mpi, &assigned[..]) + Just(mpi) => non_member(mpi, &parents) && + non_member(mpi, &moved) && + non_member(mpi, &assigned) }); - debug!("fragments 5 unmoved: {:?}", frag_lps(&unmoved[..])); + debug!("fragments 5 unmoved: {:?}", frag_lps(&unmoved)); // Swap contents back in. fragments.unmoved_fragments = unmoved; diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 20d495976b0..59c3e68aada 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -112,7 +112,7 @@ fn borrowck_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_id: hir::BodyId) { &flowed_moves.move_data, owner_id); - check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans[..], body); + check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans, body); } fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, diff --git a/src/librustc_borrowck/graphviz.rs b/src/librustc_borrowck/graphviz.rs index 0da9525efd8..e3a2bfa3927 100644 --- a/src/librustc_borrowck/graphviz.rs +++ b/src/librustc_borrowck/graphviz.rs @@ -88,7 +88,7 @@ impl<'a, 'tcx> DataflowLabeller<'a, 'tcx> { set.push_str(", "); } let loan_str = self.borrowck_ctxt.loan_path_to_string(&lp); - set.push_str(&loan_str[..]); + set.push_str(&loan_str); saw_some = true; true }); diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index 53a7e872928..c1dc5f5f7a2 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -680,10 +680,10 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>( }).collect(); let wild_patterns: Vec<_> = wild_patterns_owned.iter().collect(); let matrix = Matrix(m.iter().flat_map(|r| { - specialize(cx, &r[..], &ctor, &wild_patterns) + specialize(cx, &r, &ctor, &wild_patterns) }).collect()); match specialize(cx, v, &ctor, &wild_patterns) { - Some(v) => match is_useful(cx, &matrix, &v[..], witness) { + Some(v) => match is_useful(cx, &matrix, &v, witness) { UsefulWithWitness(witnesses) => UsefulWithWitness( witnesses.into_iter() .map(|witness| witness.apply_constructor(cx, &ctor, lty)) diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index e2b9f174ff0..9d55281d019 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -311,7 +311,7 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, for &(pat, hir_pat) in pats { let v = vec![pat]; - match is_useful(cx, &seen, &v[..], LeaveOutWitness) { + match is_useful(cx, &seen, &v, LeaveOutWitness) { NotUseful => { match source { hir::MatchSource::IfLetDesugar { .. } => { diff --git a/src/librustc_data_structures/accumulate_vec.rs b/src/librustc_data_structures/accumulate_vec.rs index d4bd9e707fd..c03c2890ba3 100644 --- a/src/librustc_data_structures/accumulate_vec.rs +++ b/src/librustc_data_structures/accumulate_vec.rs @@ -91,8 +91,8 @@ impl Deref for AccumulateVec { type Target = [A::Element]; fn deref(&self) -> &Self::Target { match *self { - AccumulateVec::Array(ref v) => &v[..], - AccumulateVec::Heap(ref v) => &v[..], + AccumulateVec::Array(ref v) => v, + AccumulateVec::Heap(ref v) => v, } } } @@ -100,8 +100,8 @@ impl Deref for AccumulateVec { impl DerefMut for AccumulateVec { fn deref_mut(&mut self) -> &mut [A::Element] { match *self { - AccumulateVec::Array(ref mut v) => &mut v[..], - AccumulateVec::Heap(ref mut v) => &mut v[..], + AccumulateVec::Array(ref mut v) => v, + AccumulateVec::Heap(ref mut v) => v, } } } diff --git a/src/librustc_data_structures/base_n.rs b/src/librustc_data_structures/base_n.rs index 4359581a897..cf54229fa7f 100644 --- a/src/librustc_data_structures/base_n.rs +++ b/src/librustc_data_structures/base_n.rs @@ -48,7 +48,7 @@ pub fn encode(n: u64, base: u64) -> String { #[test] fn test_encode() { fn test(n: u64, base: u64) { - assert_eq!(Ok(n), u64::from_str_radix(&encode(n, base)[..], base as u32)); + assert_eq!(Ok(n), u64::from_str_radix(&encode(n, base), base as u32)); } for base in 2..37 { diff --git a/src/librustc_data_structures/blake2b.rs b/src/librustc_data_structures/blake2b.rs index 31492e26219..9d97a83f693 100644 --- a/src/librustc_data_structures/blake2b.rs +++ b/src/librustc_data_structures/blake2b.rs @@ -35,7 +35,7 @@ pub struct Blake2bCtx { impl ::std::fmt::Debug for Blake2bCtx { fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { try!(write!(fmt, "hash: ")); - for v in &self.h[..] { + for v in &self.h { try!(write!(fmt, "{:x}", v)); } Ok(()) diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 2e9e054e97e..572ce98d3ae 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -91,13 +91,13 @@ impl IdxSet { impl Deref for IdxSetBuf { type Target = IdxSet; fn deref(&self) -> &IdxSet { - unsafe { IdxSet::from_slice(&self.bits[..]) } + unsafe { IdxSet::from_slice(&self.bits) } } } impl DerefMut for IdxSetBuf { fn deref_mut(&mut self) -> &mut IdxSet { - unsafe { IdxSet::from_slice_mut(&mut self.bits[..]) } + unsafe { IdxSet::from_slice_mut(&mut self.bits) } } } @@ -135,11 +135,11 @@ impl IdxSet { } pub fn words(&self) -> &[Word] { - &self.bits[..] + &self.bits } pub fn words_mut(&mut self) -> &mut [Word] { - &mut self.bits[..] + &mut self.bits } pub fn clone_from(&mut self, other: &IdxSet) { diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 68b9f85721a..e11118901d2 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -233,7 +233,7 @@ fn make_output(matches: &getopts::Matches) -> (Option, Option) // Extract input (string or file and optional path) from matches. fn make_input(free_matches: &[String]) -> Option<(Input, Option)> { if free_matches.len() == 1 { - let ifile = &free_matches[0][..]; + let ifile = &free_matches[0]; if ifile == "-" { let mut src = String::new(); io::stdin().read_to_string(&mut src).unwrap(); @@ -800,7 +800,7 @@ Available lint options: for lint in lints { let name = lint.name_lower().replace("_", "-"); println!(" {} {:7.7} {}", - padded(&name[..]), + padded(&name), lint.default_level.as_str(), lint.desc); } @@ -838,7 +838,7 @@ Available lint options: .map(|x| x.to_string().replace("_", "-")) .collect::>() .join(", "); - println!(" {} {}", padded(&name[..]), desc); + println!(" {} {}", padded(&name), desc); } println!("\n"); }; @@ -945,7 +945,7 @@ pub fn handle_options(args: &[String]) -> Option { .into_iter() .map(|x| x.opt_group) .collect(); - let matches = match getopts::getopts(&args[..], &all_groups) { + let matches = match getopts::getopts(&args, &all_groups) { Ok(m) => m, Err(f) => early_error(ErrorOutputType::default(), &f.to_string()), }; @@ -1084,7 +1084,7 @@ pub fn monitor(f: F) { format!("we would appreciate a bug report: {}", BUG_REPORT_URL)]; for note in &xs { handler.emit(&MultiSpan::new(), - ¬e[..], + ¬e, errors::Level::Note); } if match env::var_os("RUST_BACKTRACE") { diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 6cd97e95598..18dc504ca8a 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -589,7 +589,7 @@ impl UserIdentifiedItem { -> NodesMatchingUII<'a, 'hir> { match *self { ItemViaNode(node_id) => NodesMatchingDirect(Some(node_id).into_iter()), - ItemViaPath(ref parts) => NodesMatchingSuffix(map.nodes_matching_suffix(&parts[..])), + ItemViaPath(ref parts) => NodesMatchingSuffix(map.nodes_matching_suffix(&parts)), } } @@ -600,7 +600,7 @@ impl UserIdentifiedItem { user_option, self.reconstructed_input(), is_wrong_because); - sess.fatal(&message[..]) + sess.fatal(&message) }; let mut saw_node = ast::DUMMY_NODE_ID; @@ -771,7 +771,7 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, fn expand_err_details(r: io::Result<()>) -> io::Result<()> { r.map_err(|ioerr| { io::Error::new(io::ErrorKind::Other, - &format!("graphviz::render failed: {}", ioerr)[..]) + format!("graphviz::render failed: {}", ioerr)) }) } } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 9568cc3d6de..af2416f787e 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -289,7 +289,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn t_param(&self, index: u32) -> Ty<'tcx> { let name = format!("T{}", index); - self.infcx.tcx.mk_param(index, Symbol::intern(&name[..])) + self.infcx.tcx.mk_param(index, Symbol::intern(&name)) } pub fn re_early_bound(&self, index: u32, name: &'static str) -> &'tcx ty::Region { diff --git a/src/librustc_incremental/persist/file_format.rs b/src/librustc_incremental/persist/file_format.rs index b67caa6750a..5c20f65274f 100644 --- a/src/librustc_incremental/persist/file_format.rs +++ b/src/librustc_incremental/persist/file_format.rs @@ -99,9 +99,9 @@ pub fn read_file(sess: &Session, path: &Path) -> io::Result>> { let rustc_version_str_len = rustc_version_str_len[0] as usize; let mut buffer = Vec::with_capacity(rustc_version_str_len); buffer.resize(rustc_version_str_len, 0); - file.read_exact(&mut buffer[..])?; + file.read_exact(&mut buffer)?; - if &buffer[..] != rustc_version().as_bytes() { + if buffer != rustc_version().as_bytes() { report_format_mismatch(sess, path, "Different compiler version"); return Ok(None); } diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 353b86820c4..c4220e9a0d3 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -88,7 +88,7 @@ impl NonCamelCaseTypes { } else { format!("{} `{}` should have a camel case name such as `{}`", sort, name, c) }; - cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m[..]); + cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m); } } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f0276f90f27..0ee9d4a42c7 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -334,7 +334,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { attr.check_name("doc") && match attr.meta_item_list() { None => false, - Some(l) => attr::list_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 abba8afd9da..86bf209ccf8 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -146,7 +146,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { ty::TyBool => return, ty::TyAdt(def, _) => { let attrs = cx.tcx.get_attrs(def.did); - check_must_use(cx, &attrs[..], s.span) + check_must_use(cx, &attrs, s.span) } _ => false, }; diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 42717ec289c..2b945e0a3af 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -140,7 +140,7 @@ fn main() { cfg.flag(flag); } - for component in &components[..] { + for component in &components { let mut flag = String::from("-DLLVM_COMPONENT_"); flag.push_str(&component.to_uppercase()); cfg.flag(&flag); @@ -173,7 +173,7 @@ fn main() { if !is_crossed { cmd.arg("--system-libs"); } - cmd.args(&components[..]); + cmd.args(&components); for lib in output(&mut cmd).split_whitespace() { let name = if lib.starts_with("-l") { diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index e1255110a83..04a8b88f8a5 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -669,7 +669,7 @@ impl<'a> CrateLoader<'a> { name, config::host_triple(), self.sess.opts.target_triple); - span_fatal!(self.sess, span, E0456, "{}", &message[..]); + span_fatal!(self.sess, span, E0456, "{}", &message); } let root = ekrate.metadata.get_root(); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index a324c166e73..1370d69f904 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -918,14 +918,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { self.encode_fields(def_id); } hir::ItemImpl(..) => { - for &trait_item_def_id in &self.tcx.associated_item_def_ids(def_id)[..] { + for &trait_item_def_id in self.tcx.associated_item_def_ids(def_id).iter() { self.record(trait_item_def_id, EncodeContext::encode_info_for_impl_item, trait_item_def_id); } } hir::ItemTrait(..) => { - for &item_def_id in &self.tcx.associated_item_def_ids(def_id)[..] { + for &item_def_id in self.tcx.associated_item_def_ids(def_id).iter() { self.record(item_def_id, EncodeContext::encode_info_for_trait_item, item_def_id); diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index a6771083fc3..e8bc8b01652 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -477,15 +477,15 @@ impl<'a> Context<'a> { Some(file) => file, }; let (hash, found_kind) = - if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rlib") { + if file.starts_with(&rlib_prefix) && file.ends_with(".rlib") { (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], CrateFlavor::Rlib) - } else if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rmeta") { + } else if file.starts_with(&rlib_prefix) && file.ends_with(".rmeta") { (&file[(rlib_prefix.len())..(file.len() - ".rmeta".len())], CrateFlavor::Rmeta) } else if file.starts_with(&dylib_prefix) && file.ends_with(&dypair.1) { (&file[(dylib_prefix.len())..(file.len() - dypair.1.len())], CrateFlavor::Dylib) } else { - if file.starts_with(&staticlib_prefix[..]) && file.ends_with(&staticpair.1) { + if file.starts_with(&staticlib_prefix) && file.ends_with(&staticpair.1) { staticlibs.push(CrateMismatch { path: path.to_path_buf(), got: "static".to_string(), diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index 1bfc445fca9..efe9963cecc 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -126,19 +126,19 @@ impl<'a> PluginLoader<'a> { // inside this crate, so continue would spew "macro undefined" // errors Err(err) => { - self.sess.span_fatal(span, &err[..]) + self.sess.span_fatal(span, &err) } }; unsafe { let registrar = - match lib.symbol(&symbol[..]) { + match lib.symbol(&symbol) { Ok(registrar) => { mem::transmute::<*mut u8,PluginRegistrarFun>(registrar) } // again fatal if we can't register macros Err(err) => { - self.sess.span_fatal(span, &err[..]) + self.sess.span_fatal(span, &err) } }; diff --git a/src/librustc_save_analysis/csv_dumper.rs b/src/librustc_save_analysis/csv_dumper.rs index 59340ae87ee..4bab135ff12 100644 --- a/src/librustc_save_analysis/csv_dumper.rs +++ b/src/librustc_save_analysis/csv_dumper.rs @@ -423,7 +423,7 @@ fn make_values_str(pairs: &[(&'static str, &str)]) -> String { let strs = pairs.map(|(f, v)| format!(",{},\"{}\"", f, escape(String::from(v)))); strs.fold(String::new(), |mut s, ss| { - s.push_str(&ss[..]); + s.push_str(&ss); s }) } diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 27a19d211c2..1530708b4b8 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -369,7 +369,7 @@ impl FnType { match sig.inputs().last().unwrap().sty { ty::TyTuple(ref tupled_arguments, _) => { inputs = &sig.inputs()[0..sig.inputs().len() - 1]; - &tupled_arguments[..] + &tupled_arguments } _ => { bug!("argument to function with \"rust-call\" ABI \ diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 058f37f62dd..5c1ced57340 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -229,11 +229,11 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, variant_fill].iter().cloned().collect(); match name { None => { - Type::struct_(cx, &fields[..], false) + Type::struct_(cx, &fields, false) } Some(name) => { let mut llty = Type::named_struct(cx, name); - llty.set_struct_body(&fields[..], false); + llty.set_struct_body(&fields, false); llty } } @@ -330,7 +330,7 @@ fn struct_wrapped_nullable_bitdiscr( alignment: Alignment, ) -> ValueRef { let llptrptr = bcx.gepi(scrutinee, - &discrfield.iter().map(|f| *f as usize).collect::>()[..]); + &discrfield.iter().map(|f| *f as usize).collect::>()); let llptr = bcx.load(llptrptr, alignment.to_align()); let cmp = if nndiscr == 0 { IntEQ } else { IntNE }; bcx.icmp(cmp, llptr, C_null(val_ty(llptr))) @@ -402,7 +402,7 @@ pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: Valu base::call_memset(bcx, llptr, fill_byte, size, align, false); } else { let path = discrfield.iter().map(|&i| i as usize).collect::>(); - let llptrptr = bcx.gepi(val, &path[..]); + let llptrptr = bcx.gepi(val, &path); let llptrty = val_ty(llptrptr).element_type(); bcx.store(C_null(llptrty), llptrptr, None); } diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs index 12e4e57964f..b6195765b27 100644 --- a/src/librustc_trans/asm.rs +++ b/src/librustc_trans/asm.rs @@ -77,14 +77,14 @@ pub fn trans_inline_asm<'a, 'tcx>( .chain(arch_clobbers.iter().map(|s| s.to_string())) .collect::>().join(","); - debug!("Asm Constraints: {}", &all_constraints[..]); + debug!("Asm Constraints: {}", &all_constraints); // Depending on how many outputs we have, the return type is different let num_outputs = output_types.len(); let output_type = match num_outputs { 0 => Type::void(bcx.ccx), 1 => output_types[0], - _ => Type::struct_(bcx.ccx, &output_types[..], false) + _ => Type::struct_(bcx.ccx, &output_types, false) }; let dialect = match ia.dialect { diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_trans/back/archive.rs index 11ab6dcaa87..0f908b7d069 100644 --- a/src/librustc_trans/back/archive.rs +++ b/src/librustc_trans/back/archive.rs @@ -65,10 +65,10 @@ pub fn find_library(name: &str, search_paths: &[PathBuf], sess: &Session) for path in search_paths { debug!("looking for {} inside {:?}", name, path); - let test = path.join(&oslibname[..]); + let test = path.join(&oslibname); if test.exists() { return test } if oslibname != unixlibname { - let test = path.join(&unixlibname[..]); + let test = path.join(&unixlibname); if test.exists() { return test } } } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index cf1e10b317b..6d17b2f0eed 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -91,7 +91,7 @@ pub fn find_crate_name(sess: Option<&Session>, attrs: &[ast::Attribute], input: &Input) -> String { let validate = |s: String, span: Option| { - cstore::validate_crate_name(sess, &s[..], span); + cstore::validate_crate_name(sess, &s, span); s }; @@ -109,7 +109,7 @@ pub fn find_crate_name(sess: Option<&Session>, let msg = format!("--crate-name and #[crate_name] are \ required to match, but `{}` != `{}`", s, name); - sess.span_err(attr.span, &msg[..]); + sess.span_err(attr.span, &msg); } } return validate(s.clone(), None); @@ -417,7 +417,7 @@ fn object_filenames(trans: &CrateTranslation, outputs: &OutputFilenames) -> Vec { trans.modules.iter().map(|module| { - outputs.temp_path(OutputType::Object, Some(&module.name[..])) + outputs.temp_path(OutputType::Object, Some(&module.name)) }).collect() } @@ -551,7 +551,7 @@ fn link_rlib<'a>(sess: &'a Session, e)) } - let bc_data_deflated = flate::deflate_bytes(&bc_data[..]); + let bc_data_deflated = flate::deflate_bytes(&bc_data); let mut bc_file_deflated = match fs::File::create(&bc_deflated_filename) { Ok(file) => file, @@ -819,12 +819,12 @@ fn link_natively(sess: &Session, pname, prog.status)) .note(&format!("{:?}", &cmd)) - .note(&escape_string(&output[..])) + .note(&escape_string(&output)) .emit(); sess.abort_if_errors(); } - info!("linker stderr:\n{}", escape_string(&prog.stderr[..])); - info!("linker stdout:\n{}", escape_string(&prog.stdout[..])); + info!("linker stderr:\n{}", escape_string(&prog.stderr)); + info!("linker stdout:\n{}", escape_string(&prog.stdout)); }, Err(e) => { sess.struct_err(&format!("could not exec the linker `{}`: {}", pname, e)) diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 0ef3f351a2a..e23ddd2542a 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -61,7 +61,7 @@ pub fn run(sess: &session::Session, } let export_threshold = - symbol_export::crates_export_threshold(&sess.crate_types.borrow()[..]); + symbol_export::crates_export_threshold(&sess.crate_types.borrow()); let symbol_filter = &|&(ref name, level): &(String, _)| { if symbol_export::is_below_threshold(level, export_threshold) { @@ -147,7 +147,7 @@ pub fn run(sess: &session::Session, bc_decoded.len() as libc::size_t) { write::llvm_err(sess.diagnostic(), format!("failed to load bc of `{}`", - &name[..])); + name)); } }); } diff --git a/src/librustc_trans/back/rpath.rs b/src/librustc_trans/back/rpath.rs index 9c982be3fa0..104e7bc6a52 100644 --- a/src/librustc_trans/back/rpath.rs +++ b/src/librustc_trans/back/rpath.rs @@ -37,8 +37,8 @@ pub fn get_rpath_flags(config: &mut RPathConfig) -> Vec { let libs = config.used_crates.clone(); let libs = libs.into_iter().filter_map(|(_, l)| l.option()).collect::>(); - let rpaths = get_rpaths(config, &libs[..]); - flags.extend_from_slice(&rpaths_to_flags(&rpaths[..])); + let rpaths = get_rpaths(config, &libs); + flags.extend_from_slice(&rpaths_to_flags(&rpaths)); // Use DT_RUNPATH instead of DT_RPATH if available if config.linker_is_gnu { @@ -84,14 +84,14 @@ fn get_rpaths(config: &mut RPathConfig, libs: &[PathBuf]) -> Vec { } } - log_rpaths("relative", &rel_rpaths[..]); - log_rpaths("fallback", &fallback_rpaths[..]); + log_rpaths("relative", &rel_rpaths); + log_rpaths("fallback", &fallback_rpaths); let mut rpaths = rel_rpaths; - rpaths.extend_from_slice(&fallback_rpaths[..]); + rpaths.extend_from_slice(&fallback_rpaths); // Remove duplicates - let rpaths = minimize_rpaths(&rpaths[..]); + let rpaths = minimize_rpaths(&rpaths); return rpaths; } @@ -177,7 +177,7 @@ fn minimize_rpaths(rpaths: &[String]) -> Vec { let mut set = HashSet::new(); let mut minimized = Vec::new(); for rpath in rpaths { - if set.insert(&rpath[..]) { + if set.insert(rpath) { minimized.push(rpath.clone()); } } diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 005fb3533ab..23a67ef5046 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -154,7 +154,7 @@ impl ExportedSymbols { cnum: CrateNum) -> &[(String, SymbolExportLevel)] { match self.exports.get(&cnum) { - Some(exports) => &exports[..], + Some(exports) => exports, None => &[] } } @@ -167,7 +167,7 @@ impl ExportedSymbols { { for &(ref name, export_level) in self.exported_symbols(cnum) { if is_below_threshold(export_level, export_threshold) { - f(&name[..], export_level) + f(&name, export_level) } } } diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 518995dfedc..3ad04e10cb0 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -341,7 +341,7 @@ pub fn sanitize(s: &str) -> String { if !result.is_empty() && result.as_bytes()[0] != '_' as u8 && ! (result.as_bytes()[0] as char).is_xid_start() { - return format!("_{}", &result[..]); + return format!("_{}", result); } return result; diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 377ff34cb7e..5a017e4fb8a 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -105,7 +105,7 @@ impl SharedEmitter { Some(ref code) => { handler.emit_with_code(&MultiSpan::new(), &diag.msg, - &code[..], + &code, diag.lvl); }, None => { @@ -189,8 +189,8 @@ pub fn create_target_machine(sess: &Session) -> TargetMachineRef { let fdata_sections = ffunction_sections; let code_model_arg = match sess.opts.cg.code_model { - Some(ref s) => &s[..], - None => &sess.target.target.options.code_model[..], + Some(ref s) => &s, + None => &sess.target.target.options.code_model, }; let code_model = match CODE_GEN_MODEL_ARGS.iter().find( @@ -397,7 +397,7 @@ unsafe extern "C" fn inline_asm_handler(diag: SMDiagnosticRef, let msg = llvm::build_string(|s| llvm::LLVMRustWriteSMDiagnosticToString(diag, s)) .expect("non-UTF8 SMDiagnostic"); - report_inline_asm(cgcx, &msg[..], cookie); + report_inline_asm(cgcx, &msg, cookie); } unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_void) { @@ -823,7 +823,7 @@ pub fn run_passes(sess: &Session, if trans.modules.len() == 1 { // 1) Only one codegen unit. In this case it's no difficulty // to copy `foo.0.x` to `foo.x`. - let module_name = Some(&(trans.modules[0].name)[..]); + let module_name = Some(&trans.modules[0].name[..]); let path = crate_output.temp_path(output_type, module_name); copy_gracefully(&path, &crate_output.path(output_type)); @@ -939,7 +939,7 @@ pub fn run_passes(sess: &Session, if metadata_config.emit_bc && !user_wants_bitcode { let path = crate_output.temp_path(OutputType::Bitcode, - Some(&trans.metadata_module.name[..])); + Some(&trans.metadata_module.name)); remove(sess, &path); } } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index f7ca468fdda..ec45c559363 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -514,7 +514,7 @@ pub fn call_memcpy<'a, 'tcx>(b: &Builder<'a, 'tcx>, n_bytes: ValueRef, align: u32) { let ccx = b.ccx; - let ptr_width = &ccx.sess().target.target.target_pointer_width[..]; + let ptr_width = &ccx.sess().target.target.target_pointer_width; let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width); let memcpy = ccx.get_intrinsic(&key); let src_ptr = b.pointercast(src, Type::i8p(ccx)); @@ -550,7 +550,7 @@ pub fn call_memset<'a, 'tcx>(b: &Builder<'a, 'tcx>, size: ValueRef, align: ValueRef, volatile: bool) -> ValueRef { - let ptr_width = &b.ccx.sess().target.target.target_pointer_width[..]; + let ptr_width = &b.ccx.sess().target.target.target_pointer_width; let intrinsic_key = format!("llvm.memset.p0i8.i{}", ptr_width); let llintrinsicfn = b.ccx.get_intrinsic(&intrinsic_key); let volatile = C_bool(b.ccx, volatile); @@ -765,7 +765,7 @@ fn write_metadata(cx: &SharedCrateContext, let mut compressed = cstore.metadata_encoding_version().to_vec(); compressed.extend_from_slice(&flate::deflate_bytes(&metadata)); - let llmeta = C_bytes_in_context(cx.metadata_llcx(), &compressed[..]); + let llmeta = C_bytes_in_context(cx.metadata_llcx(), &compressed); let llconst = C_struct_in_context(cx.metadata_llcx(), &[llmeta], false); let name = cx.metadata_symbol_name(); let buf = CString::new(name).unwrap(); @@ -796,7 +796,7 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, symbol_map: &SymbolMap<'tcx>, exported_symbols: &ExportedSymbols) { let export_threshold = - symbol_export::crates_export_threshold(&sess.crate_types.borrow()[..]); + symbol_export::crates_export_threshold(&sess.crate_types.borrow()); let exported_symbols = exported_symbols .exported_symbols(LOCAL_CRATE) @@ -1035,7 +1035,7 @@ pub fn find_exported_symbols(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { (generics.parent_types == 0 && generics.types.is_empty()) && // Functions marked with #[inline] are only ever translated // with "internal" linkage and are never exported. - !attr::requests_inline(&attributes[..]) + !attr::requests_inline(&attributes) } _ => false @@ -1574,7 +1574,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a cgus.dedup(); for &(ref cgu_name, linkage) in cgus.iter() { output.push_str(" "); - output.push_str(&cgu_name[..]); + output.push_str(&cgu_name); let linkage_abbrev = match linkage { llvm::Linkage::ExternalLinkage => "External", diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index a62f07042a7..8b1010d89fd 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -627,7 +627,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { let v = ixs.iter().map(|i| C_i32(self.ccx, *i as i32)).collect::>(); self.count_insn("gepi"); - self.inbounds_gep(base, &v[..]) + self.inbounds_gep(base, &v) } } @@ -835,8 +835,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let s = format!("{} ({})", text, self.ccx.sess().codemap().span_to_string(sp)); - debug!("{}", &s[..]); - self.add_comment(&s[..]); + debug!("{}", s); + self.add_comment(&s); } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 5c94032c6b9..612e765a499 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2611,7 +2611,7 @@ fn render_attribute(attr: &ast::MetaItem) -> Option { if attr.is_word() { Some(format!("{}", name)) } else if let Some(v) = attr.value_str() { - Some(format!("{} = {:?}", name, &v.as_str()[..])) + Some(format!("{} = {:?}", name, v.as_str())) } else if let Some(values) = attr.meta_item_list() { let display: Vec<_> = values.iter().filter_map(|attr| { attr.meta_item().and_then(|mi| render_attribute(mi)) @@ -2642,7 +2642,7 @@ fn render_attributes(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result { for attr in &it.attrs.other_attrs { let name = attr.name().unwrap(); - if !ATTRIBUTE_WHITELIST.contains(&&name.as_str()[..]) { + if !ATTRIBUTE_WHITELIST.contains(&&*name.as_str()) { continue; } if let Some(s) = render_attribute(&attr.meta().unwrap()) { diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 021c5398a42..66f5520b882 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -119,7 +119,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, }; let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), false); p.root_module_name = cx.current_expansion.module.mod_path.last() - .map(|id| (*id.name.as_str()).to_owned()); + .map(|id| id.name.as_str().to_string()); p.check_unknown_macro_variable(); // Let the context choose how to interpret the result. diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 7af432176cf..9d280a413e6 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -818,7 +818,7 @@ pub struct GatedCfg { impl GatedCfg { pub fn gate(cfg: &ast::MetaItem) -> Option { - let name = &*cfg.name().as_str(); + let name = cfg.name().as_str(); GATED_CFGS.iter() .position(|info| info.0 == name) .map(|idx| { @@ -865,8 +865,7 @@ macro_rules! gate_feature { impl<'a> Context<'a> { fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) { debug!("check_attribute(attr = {:?})", attr); - let name = unwrap_or!(attr.name(), return); - + let name = unwrap_or!(attr.name(), return).as_str(); for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES { if name == n { if let &Gated(_, ref name, ref desc, ref has_feature) = gateage { @@ -885,12 +884,12 @@ impl<'a> Context<'a> { return; } } - if name.as_str().starts_with("rustc_") { + if name.starts_with("rustc_") { gate_feature!(self, rustc_attrs, attr.span, "unless otherwise specified, attributes \ with the prefix `rustc_` \ are reserved for internal compiler diagnostics"); - } else if name.as_str().starts_with("derive_") { + } else if name.starts_with("derive_") { gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE); } else if !attr::is_known(attr) { // Only run the custom attribute lint during regular diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 649e9059934..43a9d8c5f78 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5151,15 +5151,15 @@ impl<'a> Parser<'a> { fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) { if let Some(path) = attr::first_attr_value_str_by_name(attrs, "path") { - self.directory.path.push(&*path.as_str()); + self.directory.path.push(&path.as_str()); self.directory.ownership = DirectoryOwnership::Owned; } else { - self.directory.path.push(&*id.name.as_str()); + self.directory.path.push(&id.name.as_str()); } } pub fn submod_path_from_attr(attrs: &[ast::Attribute], dir_path: &Path) -> Option { - attr::first_attr_value_str_by_name(attrs, "path").map(|d| dir_path.join(&*d.as_str())) + attr::first_attr_value_str_by_name(attrs, "path").map(|d| dir_path.join(&d.as_str())) } /// Returns either a path to a module, or . diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index e052d2cda3a..6fb6db9ca02 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -616,7 +616,7 @@ fn mk_tests(cx: &TestCtxt) -> P { fn is_test_crate(krate: &ast::Crate) -> bool { match attr::find_crate_name(&krate.attrs) { - Some(s) if "test" == &*s.as_str() => true, + Some(s) if "test" == s.as_str() => true, _ => false } } -- cgit 1.4.1-3-g733a5 From c963d613a2275d5c9b31cd7124dda2f2af61deb6 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Mon, 27 Mar 2017 17:15:16 -0700 Subject: Simplify error output --- src/libsyntax/parse/parser.rs | 17 ++++++----------- src/test/ui/did_you_mean/issue-40006.stderr | 10 +++------- 2 files changed, 9 insertions(+), 18 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a19339f8cc1..2603b3302c6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4708,26 +4708,21 @@ impl<'a> Parser<'a> { if let Err(mut bang_err) = bang_err { // Given this code `pub path(`, it seems like this is not setting the // visibility of a macro invocation, but rather a mistyped method declaration. - // Keep the macro diagnostic, but also provide a hint that `fn` might be - // missing. Don't complain about the missing `!` as a separate diagnostic, add - // label in the appropriate place as part of one unified diagnostic. + // Create a diagnostic pointing out that `fn` is missing. // // x | pub path(&self) { - // | ^^^- - expected `!` here for a macro invocation - // | | - // | did you mean to write `fn` here for a method declaration? + // | ^ missing `fn` for method declaration + err.cancel(); bang_err.cancel(); - err.span_label(self.span, &"expected `!` here for a macro invocation"); // pub path( // ^^ `sp` below will point to this let sp = mk_sp(prev_span.hi, self.prev_span.lo); - err.span_label(sp, - &"did you mean to write `fn` here for a method declaration?"); + err = self.diagnostic() + .struct_span_err(sp, "missing `fn` for method declaration"); + err.span_label(sp, &"missing `fn`"); } return Err(err); - } else if let Err(bang_err) = bang_err { - return Err(bang_err); } // eat a matched-delimiter token tree: diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr index 93a0c58f91a..460958027ad 100644 --- a/src/test/ui/did_you_mean/issue-40006.stderr +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -1,12 +1,8 @@ -error: can't qualify macro invocation with `pub` - --> $DIR/issue-40006.rs:14:5 +error: missing `fn` for method declaration + --> $DIR/issue-40006.rs:14:8 | 14 | pub hello_method(&self) { - | ^^^- - expected `!` here for a macro invocation - | | - | did you mean to write `fn` here for a method declaration? - | - = help: try adjusting the macro to put `pub` inside the invocation + | ^ missing `fn` error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From b477682dca3343eb89a467f0d3c73986a53d49d9 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sat, 25 Mar 2017 19:06:19 -0700 Subject: Fix unittests --- src/libsyntax/parse/parser.rs | 2 +- src/libsyntax_pos/lib.rs | 4 ++-- src/test/ui/token/bounds-obj-parens.stderr | 1 + src/test/ui/token/issue-10636-2.stderr | 1 + src/test/ui/token/macro-incomplete-parse.stderr | 1 + src/test/ui/token/trailing-plus-in-bounds.stderr | 3 ++- 6 files changed, 8 insertions(+), 4 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4076368c180..8177d738dc8 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -571,7 +571,7 @@ impl<'a> Parser<'a> { label_sp }; err.span_label(sp, &label_exp); - if label_sp != self.span { + if !sp.source_equal(&self.span) { err.span_label(self.span, &"unexpected token"); } Err(err) diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 07494ff904e..0662c1c9cfd 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -81,8 +81,8 @@ impl Span { /// Returns a new span representing the next character after the end-point of this span pub fn next_point(self) -> Span { - let lo = BytePos(cmp::max(self.hi.0, self.lo.0 + 1)); - Span { lo: lo, hi: lo, expn_id: self.expn_id} + let lo = cmp::max(self.hi.0, self.lo.0 + 1); + Span { lo: BytePos(lo), hi: BytePos(lo + 1), expn_id: self.expn_id} } /// Returns `self` if `self` is not the dummy span, and `other` otherwise. diff --git a/src/test/ui/token/bounds-obj-parens.stderr b/src/test/ui/token/bounds-obj-parens.stderr index ebee363f278..4d60be15eca 100644 --- a/src/test/ui/token/bounds-obj-parens.stderr +++ b/src/test/ui/token/bounds-obj-parens.stderr @@ -5,3 +5,4 @@ error: expected one of `!` or `::`, found `` | ^^^^ expected one of `!` or `::` here error: aborting due to previous error + diff --git a/src/test/ui/token/issue-10636-2.stderr b/src/test/ui/token/issue-10636-2.stderr index 183ad30c4ef..b0bae1248b9 100644 --- a/src/test/ui/token/issue-10636-2.stderr +++ b/src/test/ui/token/issue-10636-2.stderr @@ -25,3 +25,4 @@ error: expected expression, found `)` error: main function not found error: aborting due to 4 previous errors + diff --git a/src/test/ui/token/macro-incomplete-parse.stderr b/src/test/ui/token/macro-incomplete-parse.stderr index bea00a6444c..f23d97586b8 100644 --- a/src/test/ui/token/macro-incomplete-parse.stderr +++ b/src/test/ui/token/macro-incomplete-parse.stderr @@ -29,3 +29,4 @@ note: caused by the macro expansion here; the usage of `ignored_pat!` is likely | ^^^^^^^^^^^^^^ error: aborting due to 3 previous errors + diff --git a/src/test/ui/token/trailing-plus-in-bounds.stderr b/src/test/ui/token/trailing-plus-in-bounds.stderr index 74caf8f5c2b..c765a434b8a 100644 --- a/src/test/ui/token/trailing-plus-in-bounds.stderr +++ b/src/test/ui/token/trailing-plus-in-bounds.stderr @@ -1,7 +1,8 @@ error: expected one of `!` or `::`, found `` - --> ../../src/test/ui/token/trailing-plus-in-bounds.rs:19:1 + --> $DIR/trailing-plus-in-bounds.rs:19:1 | 19 | FAIL | ^^^^ expected one of `!` or `::` here error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From ec7c0aece17c9a11bc2eca15b994355a161bf878 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 17 Mar 2017 04:04:41 +0000 Subject: Merge `ExpnId` and `SyntaxContext`. --- src/librustc/hir/lowering.rs | 7 +- src/librustc/hir/mod.rs | 5 +- src/librustc/ich/caching_codemap_view.rs | 4 - src/librustc/middle/region.rs | 2 +- src/librustc/middle/stability.rs | 2 +- src/librustc_driver/driver.rs | 4 +- src/librustc_errors/emitter.rs | 22 +- src/librustc_errors/lib.rs | 4 +- .../calculate_svh/svh_visitor.rs | 17 +- src/librustc_mir/transform/qualify_consts.rs | 4 +- src/librustc_plugin/load.rs | 4 +- src/librustc_save_analysis/lib.rs | 7 +- src/librustc_save_analysis/span_utils.rs | 3 +- src/librustc_trans/asm.rs | 4 +- src/librustc_trans/back/write.rs | 6 +- src/librustc_trans/mir/mod.rs | 18 +- src/librustc_typeck/check/mod.rs | 5 +- src/libsyntax/ast.rs | 57 +-- src/libsyntax/codemap.rs | 291 +-------------- src/libsyntax/ext/base.rs | 74 ++-- src/libsyntax/ext/derive.rs | 50 +-- src/libsyntax/ext/expand.rs | 111 +++--- src/libsyntax/ext/source_util.rs | 2 +- src/libsyntax/ext/tt/quoted.rs | 14 +- src/libsyntax/feature_gate.rs | 20 +- src/libsyntax/json.rs | 2 +- src/libsyntax/lib.rs | 2 +- src/libsyntax/parse/parser.rs | 6 +- src/libsyntax/std_inject.rs | 21 +- src/libsyntax/symbol.rs | 342 ------------------ src/libsyntax/test.rs | 21 +- src/libsyntax/test_snippet.rs | 2 +- src/libsyntax/tokenstream.rs | 16 +- src/libsyntax_ext/asm.rs | 12 +- src/libsyntax_ext/deriving/clone.rs | 2 +- src/libsyntax_ext/deriving/cmp/eq.rs | 2 +- src/libsyntax_ext/deriving/debug.rs | 4 +- src/libsyntax_ext/deriving/generic/mod.rs | 12 +- src/libsyntax_ext/deriving/mod.rs | 34 +- src/libsyntax_ext/format.rs | 3 +- src/libsyntax_ext/proc_macro_registrar.rs | 6 +- src/libsyntax_pos/hygiene.rs | 94 ++++- src/libsyntax_pos/lib.rs | 101 ++++-- src/libsyntax_pos/symbol.rs | 389 +++++++++++++++++++++ src/test/compile-fail-fulldeps/qquote.rs | 8 - src/test/run-fail-fulldeps/qquote.rs | 8 - src/test/run-pass-fulldeps/qquote.rs | 8 - 47 files changed, 793 insertions(+), 1039 deletions(-) delete mode 100644 src/libsyntax/symbol.rs create mode 100644 src/libsyntax_pos/symbol.rs (limited to 'src/libsyntax/parse') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 6ca0c971ea4..786145f3091 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -57,6 +57,7 @@ use std::mem; use syntax::attr; use syntax::ast::*; use syntax::errors; +use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::ptr::P; use syntax::codemap::{self, respan, Spanned}; use syntax::std_inject; @@ -392,7 +393,8 @@ impl<'a> LoweringContext<'a> { } fn allow_internal_unstable(&self, reason: &'static str, mut span: Span) -> Span { - span.expn_id = self.sess.codemap().record_expansion(codemap::ExpnInfo { + let mark = Mark::fresh(); + mark.set_expn_info(codemap::ExpnInfo { call_site: span, callee: codemap::NameAndSpan { format: codemap::CompilerDesugaring(Symbol::intern(reason)), @@ -400,6 +402,7 @@ impl<'a> LoweringContext<'a> { allow_internal_unstable: true, }, }); + span.ctxt = SyntaxContext::empty().apply_mark(mark); span } @@ -1986,7 +1989,7 @@ impl<'a> LoweringContext<'a> { volatile: asm.volatile, alignstack: asm.alignstack, dialect: asm.dialect, - expn_id: asm.expn_id, + ctxt: asm.ctxt, }; let outputs = asm.outputs.iter().map(|out| self.lower_expr(&out.expr)).collect(); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f4f2f4cf921..da7e71ac07d 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -33,11 +33,12 @@ use hir::def::Def; use hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; use util::nodemap::{NodeMap, FxHashSet}; -use syntax_pos::{Span, ExpnId, DUMMY_SP}; +use syntax_pos::{Span, DUMMY_SP}; use syntax::codemap::{self, Spanned}; use syntax::abi::Abi; use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect}; use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem}; +use syntax::ext::hygiene::SyntaxContext; use syntax::ptr::P; use syntax::symbol::{Symbol, keywords}; use syntax::tokenstream::TokenStream; @@ -1367,7 +1368,7 @@ pub struct InlineAsm { pub volatile: bool, pub alignstack: bool, pub dialect: AsmDialect, - pub expn_id: ExpnId, + pub ctxt: SyntaxContext, } /// represents an argument in a function header diff --git a/src/librustc/ich/caching_codemap_view.rs b/src/librustc/ich/caching_codemap_view.rs index a71251eedf5..1278d9f5171 100644 --- a/src/librustc/ich/caching_codemap_view.rs +++ b/src/librustc/ich/caching_codemap_view.rs @@ -47,10 +47,6 @@ impl<'tcx> CachingCodemapView<'tcx> { } } - pub fn codemap(&self) -> &'tcx CodeMap { - self.codemap - } - pub fn byte_pos_to_line_and_col(&mut self, pos: BytePos) -> Option<(Rc, usize, BytePos)> { diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index a19f15a9329..0676075930d 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -236,7 +236,7 @@ impl CodeExtent { // (This is the special case aluded to in the // doc-comment for this method) let stmt_span = blk.stmts[r.first_statement_index as usize].span; - Some(Span { lo: stmt_span.hi, hi: blk.span.hi, expn_id: stmt_span.expn_id }) + Some(Span { lo: stmt_span.hi, hi: blk.span.hi, ctxt: stmt_span.ctxt }) } } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 4354ed6817a..2b5ea61d4e8 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -467,7 +467,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn check_stability(self, def_id: DefId, id: NodeId, span: Span) { - if self.sess.codemap().span_allows_unstable(span) { + if span.allows_unstable() { debug!("stability: \ skipping span={:?} since it is internal", span); return; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 4873b21c548..977382b33ad 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -580,7 +580,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, krate = time(time_passes, "crate injection", || { let alt_std_name = sess.opts.alt_std_name.clone(); - syntax::std_inject::maybe_inject_crates_ref(&sess.parse_sess, krate, alt_std_name) + syntax::std_inject::maybe_inject_crates_ref(krate, alt_std_name) }); let mut addl_plugins = Some(addl_plugins); @@ -798,7 +798,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, // Discard hygiene data, which isn't required after lowering to HIR. if !keep_hygiene_data(sess) { - syntax::ext::hygiene::reset_hygiene_data(); + syntax::ext::hygiene::clear_markings(); } Ok(ExpansionResult { diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 431edb3c9bc..367b85ac726 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -10,7 +10,7 @@ use self::Destination::*; -use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, CharPos}; +use syntax_pos::{DUMMY_SP, FileMap, Span, MultiSpan, CharPos}; use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper}; use RenderSpan::*; @@ -151,7 +151,7 @@ impl EmitterWriter { if let Some(ref cm) = self.cm { for span_label in msp.span_labels() { - if span_label.span == DUMMY_SP || span_label.span == COMMAND_LINE_SP { + if span_label.span == DUMMY_SP { continue; } let lo = cm.lookup_char_pos(span_label.span.lo); @@ -615,7 +615,7 @@ impl EmitterWriter { let mut max = 0; if let Some(ref cm) = self.cm { for primary_span in msp.primary_spans() { - if primary_span != &DUMMY_SP && primary_span != &COMMAND_LINE_SP { + if primary_span != &DUMMY_SP { let hi = cm.lookup_char_pos(primary_span.hi); if hi.line > max { max = hi.line; @@ -623,7 +623,7 @@ impl EmitterWriter { } } for span_label in msp.span_labels() { - if span_label.span != DUMMY_SP && span_label.span != COMMAND_LINE_SP { + if span_label.span != DUMMY_SP { let hi = cm.lookup_char_pos(span_label.span.hi); if hi.line > max { max = hi.line; @@ -659,20 +659,20 @@ impl EmitterWriter { // First, find all the spans in <*macros> and point instead at their use site for sp in span.primary_spans() { - if (*sp == COMMAND_LINE_SP) || (*sp == DUMMY_SP) { + if *sp == DUMMY_SP { continue; } if cm.span_to_filename(sp.clone()).contains("macros>") { - let v = cm.macro_backtrace(sp.clone()); + let v = sp.macro_backtrace(); if let Some(use_site) = v.last() { before_after.push((sp.clone(), use_site.call_site.clone())); } } - for trace in cm.macro_backtrace(sp.clone()).iter().rev() { + for trace in sp.macro_backtrace().iter().rev() { // Only show macro locations that are local // and display them like a span_note if let Some(def_site) = trace.def_site_span { - if (def_site == COMMAND_LINE_SP) || (def_site == DUMMY_SP) { + if def_site == DUMMY_SP { continue; } // Check to make sure we're not in any <*macros> @@ -689,11 +689,11 @@ impl EmitterWriter { span.push_span_label(label_span, label_text); } for sp_label in span.span_labels() { - if (sp_label.span == COMMAND_LINE_SP) || (sp_label.span == DUMMY_SP) { + if sp_label.span == DUMMY_SP { continue; } if cm.span_to_filename(sp_label.span.clone()).contains("macros>") { - let v = cm.macro_backtrace(sp_label.span.clone()); + let v = sp_label.span.macro_backtrace(); if let Some(use_site) = v.last() { before_after.push((sp_label.span.clone(), use_site.call_site.clone())); } @@ -848,7 +848,7 @@ impl EmitterWriter { // Make sure our primary file comes first let primary_lo = if let (Some(ref cm), Some(ref primary_span)) = (self.cm.as_ref(), msp.primary_span().as_ref()) { - if primary_span != &&DUMMY_SP && primary_span != &&COMMAND_LINE_SP { + if primary_span != &&DUMMY_SP { cm.lookup_char_pos(primary_span.lo) } else { emit_to_destination(&buffer.render(), level, &mut self.dst)?; diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 4c889dad8ca..2efdaa57fba 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -48,7 +48,6 @@ pub mod styled_buffer; mod lock; use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION}; -use syntax_pos::MacroBacktrace; #[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub enum RenderSpan { @@ -75,7 +74,6 @@ pub trait CodeMapper { fn span_to_lines(&self, sp: Span) -> FileLinesResult; fn span_to_string(&self, sp: Span) -> String; fn span_to_filename(&self, sp: Span) -> FileName; - fn macro_backtrace(&self, span: Span) -> Vec; fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option; } @@ -120,7 +118,7 @@ impl CodeSuggestion { let bounding_span = Span { lo: lo, hi: hi, - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, }; let lines = cm.span_to_lines(bounding_span).unwrap(); assert!(!lines.lines.is_empty()); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 210803c3f32..5401b371888 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -17,9 +17,10 @@ use self::SawTraitOrImplItemComponent::*; use syntax::abi::Abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; +use syntax::ext::hygiene::SyntaxContext; use syntax::parse::token; use syntax::symbol::InternedString; -use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos}; +use syntax_pos::{Span, BytePos}; use syntax::tokenstream; use rustc::hir; use rustc::hir::*; @@ -92,10 +93,10 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { span.hi }; - let expn_kind = match span.expn_id { - NO_EXPANSION => SawSpanExpnKind::NoExpansion, - COMMAND_LINE_EXPN => SawSpanExpnKind::CommandLine, - _ => SawSpanExpnKind::SomeExpansion, + let expn_kind = if span.ctxt == SyntaxContext::empty() { + SawSpanExpnKind::NoExpansion + } else { + SawSpanExpnKind::SomeExpansion }; let loc1 = self.codemap.byte_pos_to_line_and_col(span.lo); @@ -121,8 +122,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { saw.hash(self.st); if expn_kind == SawSpanExpnKind::SomeExpansion { - let call_site = self.codemap.codemap().source_callsite(span); - self.hash_span(call_site); + self.hash_span(span.source_callsite()); } } @@ -483,7 +483,6 @@ fn saw_impl_item(ii: &ImplItemKind) -> SawTraitOrImplItemComponent { #[derive(Clone, Copy, Hash, Eq, PartialEq)] enum SawSpanExpnKind { NoExpansion, - CommandLine, SomeExpansion, } @@ -501,7 +500,7 @@ impl<'a> Hash for StableInlineAsm<'a> { volatile, alignstack, dialect, - expn_id: _, // This is used for error reporting + ctxt: _, // This is used for error reporting } = *self.0; asm.as_str().hash(state); diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index ba42804c926..9d236bd013c 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -223,7 +223,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { } // This comes from a macro that has #[allow_internal_unstable]. - if self.tcx.sess.codemap().span_allows_unstable(self.span) { + if self.span.allows_unstable() { return; } @@ -805,7 +805,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { self.def_id.is_local() && // this doesn't come from a macro that has #[allow_internal_unstable] - !self.tcx.sess.codemap().span_allows_unstable(self.span) + !self.span.allows_unstable() { let mut err = self.tcx.sess.struct_span_err(self.span, "const fns are an unstable feature"); diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index efe9963cecc..e884f3bdbb1 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_pos::{Span, COMMAND_LINE_SP}; +use syntax_pos::{Span, DUMMY_SP}; /// Pointer to a registrar function. pub type PluginRegistrarFun = @@ -81,7 +81,7 @@ pub fn load_plugins(sess: &Session, if let Some(plugins) = addl_plugins { for plugin in plugins { - loader.load_plugin(COMMAND_LINE_SP, &plugin, vec![]); + loader.load_plugin(DUMMY_SP, &plugin, vec![]); } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index e5c04f6b61e..fd6803e087a 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -690,9 +690,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { // Note we take care to use the source callsite/callee, to handle // nested expansions and ensure we only generate data for source-visible // macro uses. - let callsite = self.tcx.sess.codemap().source_callsite(span); - let callee = self.tcx.sess.codemap().source_callee(span); - let callee = option_try!(callee); + let callsite = span.source_callsite(); + let callee = option_try!(span.source_callee()); let callee_span = option_try!(callee.span); // Ignore attribute macros, their spans are usually mangled @@ -1013,5 +1012,5 @@ fn escape(s: String) -> String { // Helper function to determine if a span came from a // macro expansion or syntax extension. pub fn generated_code(span: Span) -> bool { - span.expn_id != NO_EXPANSION || span == DUMMY_SP + span.ctxt != NO_EXPANSION || span == DUMMY_SP } diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index 34402742e6c..c19f805a285 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -462,8 +462,7 @@ impl<'a> SpanUtils<'a> { // Otherwise, a generated span is deemed invalid if it is not a sub-span of the root // callsite. This filters out macro internal variables and most malformed spans. - let span = self.sess.codemap().source_callsite(parent); - !(span.contains(parent)) + !parent.source_callsite().contains(parent) } } diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs index b6195765b27..3e270b7928e 100644 --- a/src/librustc_trans/asm.rs +++ b/src/librustc_trans/asm.rs @@ -111,14 +111,14 @@ pub fn trans_inline_asm<'a, 'tcx>( bcx.store(v, val, None); } - // Store expn_id in a metadata node so we can map LLVM errors + // Store mark in a metadata node so we can map LLVM errors // back to source locations. See #17552. unsafe { let key = "srcloc"; let kind = llvm::LLVMGetMDKindIDInContext(bcx.ccx.llcx(), key.as_ptr() as *const c_char, key.len() as c_uint); - let val: llvm::ValueRef = C_i32(bcx.ccx, ia.expn_id.into_u32() as i32); + let val: llvm::ValueRef = C_i32(bcx.ccx, ia.ctxt.outer().as_u32() as i32); llvm::LLVMSetMetadata(r, kind, llvm::LLVMMDNodeInContext(bcx.ccx.llcx(), &val, 1)); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 5a017e4fb8a..ccb3f7ac882 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -371,14 +371,14 @@ struct HandlerFreeVars<'a> { unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext<'a>, msg: &'b str, cookie: c_uint) { - use syntax_pos::ExpnId; + use syntax::ext::hygiene::Mark; match cgcx.lto_ctxt { Some((sess, _)) => { - sess.codemap().with_expn_info(ExpnId::from_u32(cookie), |info| match info { + match Mark::from_u32(cookie).expn_info() { Some(ei) => sess.span_err(ei.call_site, msg), None => sess.err(msg), - }); + }; } None => { diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 6419f41f86b..21bbbea77d4 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -26,7 +26,7 @@ use monomorphize::{self, Instance}; use abi::FnType; use type_of; -use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, Span}; +use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span}; use syntax::symbol::keywords; use std::iter; @@ -124,24 +124,18 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { // In order to have a good line stepping behavior in debugger, we overwrite debug // locations of macro expansions with that of the outermost expansion site // (unless the crate is being compiled with `-Z debug-macros`). - if source_info.span.expn_id == NO_EXPANSION || - source_info.span.expn_id == COMMAND_LINE_EXPN || - self.ccx.sess().opts.debugging_opts.debug_macros { - + if source_info.span.ctxt == NO_EXPANSION || + self.ccx.sess().opts.debugging_opts.debug_macros { let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo); (scope, source_info.span) } else { - let cm = self.ccx.sess().codemap(); // Walk up the macro expansion chain until we reach a non-expanded span. // We also stop at the function body level because no line stepping can occurr // at the level above that. let mut span = source_info.span; - while span.expn_id != NO_EXPANSION && - span.expn_id != COMMAND_LINE_EXPN && - span.expn_id != self.mir.span.expn_id { - if let Some(callsite_span) = cm.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.call_site.clone())) { - span = callsite_span; + while span.ctxt != NO_EXPANSION && span.ctxt != self.mir.span.ctxt { + if let Some(info) = span.ctxt.outer().expn_info() { + span = info.call_site; } else { break; } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9c62fd486d4..b95e01f4ff6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4161,12 +4161,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } if let Some(last_stmt) = extra_semi { - let original_span = original_sp(self.tcx.sess.codemap(), - last_stmt.span, blk.span); + let original_span = original_sp(last_stmt.span, blk.span); let span_semi = Span { lo: original_span.hi - BytePos(1), hi: original_span.hi, - expn_id: original_span.expn_id + ctxt: original_span.ctxt, }; err.span_help(span_semi, "consider removing this semicolon:"); } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 7e2b225193f..a4bebd311de 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -14,10 +14,10 @@ pub use self::TyParamBound::*; pub use self::UnsafeSource::*; pub use self::ViewPath_::*; pub use self::PathParameters::*; -pub use symbol::Symbol as Name; +pub use symbol::{Ident, Symbol as Name}; pub use util::ThinVec; -use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP, ExpnId}; +use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP}; use codemap::{respan, Spanned}; use abi::Abi; use ext::hygiene::{Mark, SyntaxContext}; @@ -27,61 +27,12 @@ use rustc_data_structures::indexed_vec; use symbol::{Symbol, keywords}; use tokenstream::{ThinTokenStream, TokenStream}; +use serialize::{self, Encoder, Decoder}; use std::collections::HashSet; use std::fmt; use std::rc::Rc; use std::u32; -use serialize::{self, Encodable, Decodable, Encoder, Decoder}; - -/// An identifier contains a Name (index into the interner -/// table) and a SyntaxContext to track renaming and -/// macro expansion per Flatt et al., "Macros That Work Together" -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct Ident { - pub name: Symbol, - pub ctxt: SyntaxContext -} - -impl Ident { - pub const fn with_empty_ctxt(name: Name) -> Ident { - Ident { name: name, ctxt: SyntaxContext::empty() } - } - - /// Maps a string to an identifier with an empty syntax context. - pub fn from_str(s: &str) -> Ident { - Ident::with_empty_ctxt(Symbol::intern(s)) - } - - pub fn unhygienize(&self) -> Ident { - Ident { name: self.name, ctxt: SyntaxContext::empty() } - } -} - -impl fmt::Debug for Ident { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}{:?}", self.name, self.ctxt) - } -} - -impl fmt::Display for Ident { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.name, f) - } -} - -impl Encodable for Ident { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - self.name.encode(s) - } -} - -impl Decodable for Ident { - fn decode(d: &mut D) -> Result { - Ok(Ident::with_empty_ctxt(Name::decode(d)?)) - } -} - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)] pub struct Lifetime { pub id: NodeId, @@ -1445,7 +1396,7 @@ pub struct InlineAsm { pub volatile: bool, pub alignstack: bool, pub dialect: AsmDialect, - pub expn_id: ExpnId, + pub ctxt: SyntaxContext, } /// An argument in a function header. diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 388f3cb7323..ba199eacb62 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -17,6 +17,8 @@ //! within the CodeMap, which upon request can be converted to line and column //! information, source code snippets, etc. +pub use syntax_pos::*; +pub use syntax_pos::hygiene::{ExpnFormat, ExpnInfo, NameAndSpan}; pub use self::ExpnFormat::*; use std::cell::RefCell; @@ -26,35 +28,21 @@ use std::rc::Rc; use std::env; use std::fs; use std::io::{self, Read}; -pub use syntax_pos::*; use errors::CodeMapper; -use ast::Name; - /// Return the span itself if it doesn't come from a macro expansion, /// otherwise return the call site span up to the `enclosing_sp` by /// following the `expn_info` chain. -pub fn original_sp(cm: &CodeMap, sp: Span, enclosing_sp: Span) -> Span { - let call_site1 = cm.with_expn_info(sp.expn_id, |ei| ei.map(|ei| ei.call_site)); - let call_site2 = cm.with_expn_info(enclosing_sp.expn_id, |ei| ei.map(|ei| ei.call_site)); +pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span { + let call_site1 = sp.ctxt.outer().expn_info().map(|ei| ei.call_site); + let call_site2 = enclosing_sp.ctxt.outer().expn_info().map(|ei| ei.call_site); match (call_site1, call_site2) { (None, _) => sp, (Some(call_site1), Some(call_site2)) if call_site1 == call_site2 => sp, - (Some(call_site1), _) => original_sp(cm, call_site1, enclosing_sp), + (Some(call_site1), _) => original_sp(call_site1, enclosing_sp), } } -/// The source of expansion. -#[derive(Clone, Hash, Debug, PartialEq, Eq)] -pub enum ExpnFormat { - /// e.g. #[derive(...)] - MacroAttribute(Name), - /// e.g. `format!()` - MacroBang(Name), - /// Desugaring done by the compiler during HIR lowering. - CompilerDesugaring(Name) -} - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub struct Spanned { pub node: T, @@ -73,47 +61,6 @@ pub fn dummy_spanned(t: T) -> Spanned { respan(DUMMY_SP, t) } -#[derive(Clone, Hash, Debug)] -pub struct NameAndSpan { - /// The format with which the macro was invoked. - pub format: ExpnFormat, - /// Whether the macro is allowed to use #[unstable]/feature-gated - /// features internally without forcing the whole crate to opt-in - /// to them. - pub allow_internal_unstable: bool, - /// The span of the macro definition itself. The macro may not - /// have a sensible definition span (e.g. something defined - /// completely inside libsyntax) in which case this is None. - pub span: Option -} - -impl NameAndSpan { - pub fn name(&self) -> Name { - match self.format { - ExpnFormat::MacroAttribute(s) | - ExpnFormat::MacroBang(s) | - ExpnFormat::CompilerDesugaring(s) => s, - } - } -} - -/// Extra information for tracking spans of macro and syntax sugar expansion -#[derive(Hash, Debug)] -pub struct ExpnInfo { - /// The location of the actual macro invocation or syntax sugar , e.g. - /// `let x = foo!();` or `if let Some(y) = x {}` - /// - /// This may recursively refer to other macro invocations, e.g. if - /// `foo!()` invoked `bar!()` internally, and there was an - /// expression inside `bar!`; the call_site of the expression in - /// the expansion would point to the `bar!` invocation; that - /// call_site span would have its own ExpnInfo, with the call_site - /// pointing to the `foo!` invocation. - pub call_site: Span, - /// Information about the expansion. - pub callee: NameAndSpan -} - // _____________________________________________________________________________ // FileMap, MultiByteChar, FileName, FileLines // @@ -161,7 +108,6 @@ impl FileLoader for RealFileLoader { pub struct CodeMap { pub files: RefCell>>, - expansions: RefCell>, file_loader: Box } @@ -169,7 +115,6 @@ impl CodeMap { pub fn new() -> CodeMap { CodeMap { files: RefCell::new(Vec::new()), - expansions: RefCell::new(Vec::new()), file_loader: Box::new(RealFileLoader) } } @@ -177,7 +122,6 @@ impl CodeMap { pub fn with_file_loader(file_loader: Box) -> CodeMap { CodeMap { files: RefCell::new(Vec::new()), - expansions: RefCell::new(Vec::new()), file_loader: file_loader } } @@ -353,14 +297,14 @@ impl CodeMap { /// Returns `Some(span)`, a union of the lhs and rhs span. The lhs must precede the rhs. If /// there are gaps between lhs and rhs, the resulting union will cross these gaps. /// For this to work, the spans have to be: - /// * the expn_id of both spans much match + /// * the ctxt of both spans much match /// * the lhs span needs to end on the same line the rhs span begins /// * the lhs span must start at or before the rhs span pub fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option { use std::cmp; // make sure we're at the same expansion id - if sp_lhs.expn_id != sp_rhs.expn_id { + if sp_lhs.ctxt != sp_rhs.ctxt { return None; } @@ -383,7 +327,7 @@ impl CodeMap { Some(Span { lo: cmp::min(sp_lhs.lo, sp_rhs.lo), hi: cmp::max(sp_lhs.hi, sp_rhs.hi), - expn_id: sp_lhs.expn_id, + ctxt: sp_lhs.ctxt, }) } else { None @@ -391,10 +335,6 @@ impl CodeMap { } pub fn span_to_string(&self, sp: Span) -> String { - if sp == COMMAND_LINE_SP { - return "".to_string(); - } - if self.files.borrow().is_empty() && sp.source_equal(&DUMMY_SP) { return "no-location".to_string(); } @@ -409,62 +349,6 @@ impl CodeMap { hi.col.to_usize() + 1)).to_string() } - /// Return the source span - this is either the supplied span, or the span for - /// the macro callsite that expanded to it. - pub fn source_callsite(&self, sp: Span) -> Span { - let mut span = sp; - // Special case - if a macro is parsed as an argument to another macro, the source - // callsite is the first callsite, which is also source-equivalent to the span. - let mut first = true; - while span.expn_id != NO_EXPANSION && span.expn_id != COMMAND_LINE_EXPN { - if let Some(callsite) = self.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.call_site.clone())) { - if first && span.source_equal(&callsite) { - if self.lookup_char_pos(span.lo).file.is_real_file() { - return Span { expn_id: NO_EXPANSION, .. span }; - } - } - first = false; - span = callsite; - } - else { - break; - } - } - span - } - - /// Return the source callee. - /// - /// Returns None if the supplied span has no expansion trace, - /// else returns the NameAndSpan for the macro definition - /// corresponding to the source callsite. - pub fn source_callee(&self, sp: Span) -> Option { - let mut span = sp; - // Special case - if a macro is parsed as an argument to another macro, the source - // callsite is source-equivalent to the span, and the source callee is the first callee. - let mut first = true; - while let Some(callsite) = self.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.call_site.clone())) { - if first && span.source_equal(&callsite) { - if self.lookup_char_pos(span.lo).file.is_real_file() { - return self.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.callee.clone())); - } - } - first = false; - if let Some(_) = self.with_expn_info(callsite.expn_id, - |ei| ei.map(|ei| ei.call_site.clone())) { - span = callsite; - } - else { - return self.with_expn_info(span.expn_id, - |ei| ei.map(|ei| ei.callee.clone())); - } - } - None - } - pub fn span_to_filename(&self, sp: Span) -> FileName { self.lookup_char_pos(sp.lo).file.name.to_string() } @@ -628,111 +512,9 @@ impl CodeMap { return a; } - pub fn record_expansion(&self, expn_info: ExpnInfo) -> ExpnId { - let mut expansions = self.expansions.borrow_mut(); - expansions.push(expn_info); - let len = expansions.len(); - if len > u32::max_value() as usize { - panic!("too many ExpnInfo's!"); - } - ExpnId(len as u32 - 1) - } - - pub fn with_expn_info(&self, id: ExpnId, f: F) -> T where - F: FnOnce(Option<&ExpnInfo>) -> T, - { - match id { - NO_EXPANSION | COMMAND_LINE_EXPN => f(None), - ExpnId(i) => f(Some(&(*self.expansions.borrow())[i as usize])) - } - } - - /// Check if a span is "internal" to a macro in which #[unstable] - /// items can be used (that is, a macro marked with - /// `#[allow_internal_unstable]`). - pub fn span_allows_unstable(&self, span: Span) -> bool { - debug!("span_allows_unstable(span = {:?})", span); - let mut allows_unstable = false; - let mut expn_id = span.expn_id; - loop { - let quit = self.with_expn_info(expn_id, |expninfo| { - debug!("span_allows_unstable: expninfo = {:?}", expninfo); - expninfo.map_or(/* hit the top level */ true, |info| { - - let span_comes_from_this_expansion = - info.callee.span.map_or(span.source_equal(&info.call_site), |mac_span| { - mac_span.contains(span) - }); - - debug!("span_allows_unstable: span: {:?} call_site: {:?} callee: {:?}", - (span.lo, span.hi), - (info.call_site.lo, info.call_site.hi), - info.callee.span.map(|x| (x.lo, x.hi))); - debug!("span_allows_unstable: from this expansion? {}, allows unstable? {}", - span_comes_from_this_expansion, - info.callee.allow_internal_unstable); - if span_comes_from_this_expansion { - allows_unstable = info.callee.allow_internal_unstable; - // we've found the right place, stop looking - true - } else { - // not the right place, keep looking - expn_id = info.call_site.expn_id; - false - } - }) - }); - if quit { - break - } - } - debug!("span_allows_unstable? {}", allows_unstable); - allows_unstable - } - pub fn count_lines(&self) -> usize { self.files.borrow().iter().fold(0, |a, f| a + f.count_lines()) } - - pub fn macro_backtrace(&self, span: Span) -> Vec { - let mut prev_span = DUMMY_SP; - let mut span = span; - let mut result = vec![]; - loop { - let span_name_span = self.with_expn_info(span.expn_id, |expn_info| { - expn_info.map(|ei| { - let (pre, post) = match ei.callee.format { - MacroAttribute(..) => ("#[", "]"), - MacroBang(..) => ("", "!"), - CompilerDesugaring(..) => ("desugaring of `", "`"), - }; - let macro_decl_name = format!("{}{}{}", - pre, - ei.callee.name(), - post); - let def_site_span = ei.callee.span; - (ei.call_site, macro_decl_name, def_site_span) - }) - }); - - match span_name_span { - None => break, - Some((call_site, macro_decl_name, def_site_span)) => { - // Don't print recursive invocations - if !call_site.source_equal(&prev_span) { - result.push(MacroBacktrace { - call_site: call_site, - macro_decl_name: macro_decl_name, - def_site_span: def_site_span, - }); - } - prev_span = span; - span = call_site; - } - } - } - result - } } impl CodeMapper for CodeMap { @@ -748,9 +530,6 @@ impl CodeMapper for CodeMap { fn span_to_filename(&self, sp: Span) -> FileName { self.span_to_filename(sp) } - fn macro_backtrace(&self, span: Span) -> Vec { - self.macro_backtrace(span) - } fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option { self.merge_spans(sp_lhs, sp_rhs) } @@ -763,7 +542,6 @@ impl CodeMapper for CodeMap { #[cfg(test)] mod tests { use super::*; - use symbol::keywords; use std::rc::Rc; #[test] @@ -912,7 +690,7 @@ mod tests { fn t7() { // Test span_to_lines for a span ending at the end of filemap let cm = init_code_map(); - let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION}; + let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION}; let file_lines = cm.span_to_lines(span).unwrap(); assert_eq!(file_lines.file.name, "blork.rs"); @@ -928,7 +706,7 @@ mod tests { assert_eq!(input.len(), selection.len()); let left_index = selection.find('~').unwrap() as u32; let right_index = selection.rfind('~').map(|x|x as u32).unwrap_or(left_index); - Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION } + Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), ctxt: NO_EXPANSION } } /// Test span_to_snippet and span_to_lines for a span coverting 3 @@ -958,7 +736,7 @@ mod tests { fn t8() { // Test span_to_snippet for a span ending at the end of filemap let cm = init_code_map(); - let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION}; + let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION}; let snippet = cm.span_to_snippet(span); assert_eq!(snippet, Ok("second line".to_string())); @@ -968,7 +746,7 @@ mod tests { fn t9() { // Test span_to_str for a span ending at the end of filemap let cm = init_code_map(); - let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION}; + let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION}; let sstr = cm.span_to_string(span); assert_eq!(sstr, "blork.rs:2:1: 2:12"); @@ -1022,7 +800,7 @@ mod tests { let span = Span { lo: BytePos(lo as u32 + file.start_pos.0), hi: BytePos(hi as u32 + file.start_pos.0), - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, }; assert_eq!(&self.span_to_snippet(span).unwrap()[..], substring); @@ -1032,45 +810,4 @@ mod tests { } } } - - fn init_expansion_chain(cm: &CodeMap) -> Span { - // Creates an expansion chain containing two recursive calls - // root -> expA -> expA -> expB -> expB -> end - let root = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION }; - - let format_root = ExpnFormat::MacroBang(keywords::Invalid.name()); - let callee_root = NameAndSpan { format: format_root, - allow_internal_unstable: false, - span: Some(root) }; - - let info_a1 = ExpnInfo { call_site: root, callee: callee_root }; - let id_a1 = cm.record_expansion(info_a1); - let span_a1 = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id_a1 }; - - let format_a = ExpnFormat::MacroBang(keywords::As.name()); - let callee_a = NameAndSpan { format: format_a, - allow_internal_unstable: false, - span: Some(span_a1) }; - - let info_a2 = ExpnInfo { call_site: span_a1, callee: callee_a.clone() }; - let id_a2 = cm.record_expansion(info_a2); - let span_a2 = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id_a2 }; - - let info_b1 = ExpnInfo { call_site: span_a2, callee: callee_a }; - let id_b1 = cm.record_expansion(info_b1); - let span_b1 = Span { lo: BytePos(25), hi: BytePos(36), expn_id: id_b1 }; - - let format_b = ExpnFormat::MacroBang(keywords::Box.name()); - let callee_b = NameAndSpan { format: format_b, - allow_internal_unstable: false, - span: None }; - - let info_b2 = ExpnInfo { call_site: span_b1, callee: callee_b.clone() }; - let id_b2 = cm.record_expansion(info_b2); - let span_b2 = Span { lo: BytePos(25), hi: BytePos(36), expn_id: id_b2 }; - - let info_end = ExpnInfo { call_site: span_b2, callee: callee_b }; - let id_end = cm.record_expansion(info_end); - Span { lo: BytePos(37), hi: BytePos(48), expn_id: id_end } - } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index dc7e7673eb0..a2d54b62ec6 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -12,11 +12,11 @@ pub use self::SyntaxExtension::{MultiDecorator, MultiModifier, NormalTT, IdentTT use ast::{self, Attribute, Name, PatKind, MetaItem}; use attr::HasAttrs; -use codemap::{self, CodeMap, ExpnInfo, Spanned, respan}; -use syntax_pos::{Span, ExpnId, NO_EXPANSION}; -use errors::{DiagnosticBuilder, FatalError}; +use codemap::{self, CodeMap, Spanned, respan}; +use syntax_pos::{Span, DUMMY_SP}; +use errors::DiagnosticBuilder; use ext::expand::{self, Expansion, Invocation}; -use ext::hygiene::Mark; +use ext::hygiene::{Mark, SyntaxContext}; use fold::{self, Folder}; use parse::{self, parser, DirectoryOwnership}; use parse::token; @@ -56,6 +56,14 @@ impl HasAttrs for Annotatable { } impl Annotatable { + pub fn span(&self) -> Span { + match *self { + Annotatable::Item(ref item) => item.span, + Annotatable::TraitItem(ref trait_item) => trait_item.span, + Annotatable::ImplItem(ref impl_item) => impl_item.span, + } + } + pub fn expect_item(self) -> P { match self { Annotatable::Item(i) => i, @@ -602,7 +610,6 @@ pub struct ModuleData { pub struct ExpansionData { pub mark: Mark, pub depth: usize, - pub backtrace: ExpnId, pub module: Rc, pub directory_ownership: DirectoryOwnership, } @@ -633,7 +640,6 @@ impl<'a> ExtCtxt<'a> { current_expansion: ExpansionData { mark: Mark::root(), depth: 0, - backtrace: NO_EXPANSION, module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }), directory_ownership: DirectoryOwnership::Owned, }, @@ -658,30 +664,30 @@ impl<'a> ExtCtxt<'a> { pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess } pub fn cfg(&self) -> &ast::CrateConfig { &self.parse_sess.config } pub fn call_site(&self) -> Span { - self.codemap().with_expn_info(self.backtrace(), |ei| match ei { + match self.current_expansion.mark.expn_info() { Some(expn_info) => expn_info.call_site, - None => self.bug("missing top span") - }) + None => DUMMY_SP, + } + } + pub fn backtrace(&self) -> SyntaxContext { + SyntaxContext::empty().apply_mark(self.current_expansion.mark) } - pub fn backtrace(&self) -> ExpnId { self.current_expansion.backtrace } /// Returns span for the macro which originally caused the current expansion to happen. /// /// Stops backtracing at include! boundary. pub fn expansion_cause(&self) -> Span { - let mut expn_id = self.backtrace(); + let mut ctxt = self.backtrace(); let mut last_macro = None; loop { - if self.codemap().with_expn_info(expn_id, |info| { - info.map_or(None, |i| { - if i.callee.name() == "include" { - // Stop going up the backtrace once include! is encountered - return None; - } - expn_id = i.call_site.expn_id; - last_macro = Some(i.call_site); - return Some(()); - }) + if ctxt.outer().expn_info().map_or(None, |info| { + if info.callee.name() == "include" { + // Stop going up the backtrace once include! is encountered + return None; + } + ctxt = info.call_site.ctxt; + last_macro = Some(info.call_site); + return Some(()); }).is_none() { break } @@ -689,28 +695,6 @@ impl<'a> ExtCtxt<'a> { last_macro.expect("missing expansion backtrace") } - pub fn bt_push(&mut self, ei: ExpnInfo) { - if self.current_expansion.depth > self.ecfg.recursion_limit { - let suggested_limit = self.ecfg.recursion_limit * 2; - let mut err = self.struct_span_fatal(ei.call_site, - &format!("recursion limit reached while expanding the macro `{}`", - ei.callee.name())); - err.help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", - suggested_limit)); - err.emit(); - panic!(FatalError); - } - - let mut call_site = ei.call_site; - call_site.expn_id = self.backtrace(); - self.current_expansion.backtrace = self.codemap().record_expansion(ExpnInfo { - call_site: call_site, - callee: ei.callee - }); - } - pub fn bt_pop(&mut self) {} - pub fn struct_span_warn(&self, sp: Span, msg: &str) @@ -792,9 +776,9 @@ impl<'a> ExtCtxt<'a> { /// compilation on error, merely emits a non-fatal error and returns None. pub fn expr_to_spanned_string(cx: &mut ExtCtxt, expr: P, err_msg: &str) -> Option> { - // Update `expr.span`'s expn_id now in case expr is an `include!` macro invocation. + // Update `expr.span`'s ctxt now in case expr is an `include!` macro invocation. let expr = expr.map(|mut expr| { - expr.span.expn_id = cx.backtrace(); + expr.span.ctxt = expr.span.ctxt.apply_mark(cx.current_expansion.mark); expr }); diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 1569d9f540b..c79040424f6 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -9,13 +9,16 @@ // except according to those terms. use attr::HasAttrs; -use {ast, codemap}; +use ast; +use codemap::{ExpnInfo, NameAndSpan, ExpnFormat}; use ext::base::ExtCtxt; use ext::build::AstBuilder; use parse::parser::PathStyle; use symbol::Symbol; use syntax_pos::Span; +use std::collections::HashSet; + pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec { let mut result = Vec::new(); attrs.retain(|attr| { @@ -41,36 +44,35 @@ pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec result } -fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span { - Span { - expn_id: cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: span, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(Symbol::intern(attr_name)), - span: Some(span), - allow_internal_unstable: true, - }, - }), - ..span +pub fn add_derived_markers(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path], item: T) -> T + where T: HasAttrs, +{ + let (mut names, mut pretty_name) = (HashSet::new(), "derive(".to_owned()); + for (i, path) in traits.iter().enumerate() { + if i > 0 { + pretty_name.push_str(", "); + } + pretty_name.push_str(&path.to_string()); + names.insert(unwrap_or!(path.segments.get(0), continue).identifier.name); } -} + pretty_name.push(')'); -pub fn add_derived_markers(cx: &mut ExtCtxt, traits: &[ast::Path], item: T) -> T { - let span = match traits.get(0) { - Some(path) => path.span, - None => return item, - }; + cx.current_expansion.mark.set_expn_info(ExpnInfo { + call_site: span, + callee: NameAndSpan { + format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)), + span: None, + allow_internal_unstable: true, + }, + }); + let span = Span { ctxt: cx.backtrace(), ..span }; item.map_attrs(|mut attrs| { - if traits.iter().any(|path| *path == "PartialEq") && - traits.iter().any(|path| *path == "Eq") { - let span = allow_unstable(cx, span, "derive(PartialEq, Eq)"); + if names.contains(&Symbol::intern("Eq")) && names.contains(&Symbol::intern("PartialEq")) { let meta = cx.meta_word(span, Symbol::intern("structural_match")); attrs.push(cx.attribute(span, meta)); } - if traits.iter().any(|path| *path == "Copy") && - traits.iter().any(|path| *path == "Clone") { - let span = allow_unstable(cx, span, "derive(Copy, Clone)"); + if names.contains(&Symbol::intern("Copy")) && names.contains(&Symbol::intern("Clone")) { let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker")); attrs.push(cx.attribute(span, meta)); } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index e258c51a329..1b3352f73ad 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -13,6 +13,7 @@ use ast::{MacStmtStyle, StmtKind, ItemKind}; use attr::{self, HasAttrs}; use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; use config::{is_test_or_bench, StripUnconfigured}; +use errors::FatalError; use ext::base::*; use ext::derive::{add_derived_markers, collect_derives}; use ext::hygiene::Mark; @@ -27,7 +28,7 @@ use ptr::P; use std_inject; use symbol::Symbol; use symbol::keywords; -use syntax_pos::{Span, ExpnId, DUMMY_SP}; +use syntax_pos::{Span, DUMMY_SP}; use tokenstream::TokenStream; use util::small_vector::SmallVector; use visit::Visitor; @@ -273,7 +274,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let item = item .map_attrs(|mut attrs| { attrs.retain(|a| a.path != "derive"); attrs }); let item_with_markers = - add_derived_markers(&mut self.cx, &traits, item.clone()); + add_derived_markers(&mut self.cx, item.span(), &traits, item.clone()); let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new); for path in &traits { @@ -363,11 +364,26 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } fn expand_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { - match invoc.kind { + let result = match invoc.kind { InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext), InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext), InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext), + }; + + if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit { + let info = self.cx.current_expansion.mark.expn_info().unwrap(); + let suggested_limit = self.cx.ecfg.recursion_limit * 2; + let mut err = self.cx.struct_span_fatal(info.call_site, + &format!("recursion limit reached while expanding the macro `{}`", + info.callee.name())); + err.help(&format!( + "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", + suggested_limit)); + err.emit(); + panic!(FatalError); } + + result } fn expand_attr_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { @@ -378,11 +394,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; attr::mark_used(&attr); - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: attr.span, callee: NameAndSpan { format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))), - span: Some(attr.span), + span: None, allow_internal_unstable: false, } }); @@ -403,19 +419,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { SyntaxExtension::AttrProcMacro(ref mac) => { let item_toks = stream_for_item(&item, &self.cx.parse_sess); - let span = Span { - expn_id: self.cx.codemap().record_expansion(ExpnInfo { - call_site: attr.span, - callee: NameAndSpan { - format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))), - span: None, - allow_internal_unstable: false, - }, - }), - ..attr.span - }; - - let tok_result = mac.expand(self.cx, attr.span, attr.tokens.clone(), item_toks); + let span = Span { ctxt: self.cx.backtrace(), ..attr.span }; + let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_toks); self.parse_expansion(tok_result, kind, &attr.path, span) } SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => { @@ -440,8 +445,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let path = &mac.node.path; let ident = ident.unwrap_or(keywords::Invalid.ident()); - let marked_tts = - noop_fold_tts(mac.node.stream(), &mut Marker { mark: mark, expn_id: None }); + let marked_tts = noop_fold_tts(mac.node.stream(), &mut Marker(mark)); let opt_expanded = match *ext { NormalTT(ref expandfun, exp_span, allow_internal_unstable) => { if ident.name != keywords::Invalid.name() { @@ -451,7 +455,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); } - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: span, callee: NameAndSpan { format: MacroBang(Symbol::intern(&format!("{}", path))), @@ -470,7 +474,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); }; - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: span, callee: NameAndSpan { format: MacroBang(Symbol::intern(&format!("{}", path))), @@ -502,7 +506,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); } - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: span, callee: NameAndSpan { format: MacroBang(Symbol::intern(&format!("{}", path))), @@ -528,10 +532,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); }; - expanded.fold_with(&mut Marker { - mark: mark, - expn_id: Some(self.cx.backtrace()), - }) + expanded.fold_with(&mut Marker(mark)) } /// Expand a derive invocation. Returns the result of expansion. @@ -550,50 +551,33 @@ impl<'a, 'b> MacroExpander<'a, 'b> { id: ast::AttrId(0), style: ast::AttrStyle::Outer, is_sugared_doc: false, }; - self.cx.bt_push(ExpnInfo { + let mut expn_info = ExpnInfo { call_site: span, callee: NameAndSpan { format: MacroAttribute(pretty_name), span: None, allow_internal_unstable: false, } - }); + }; match *ext { SyntaxExtension::ProcMacroDerive(ref ext, _) => { - let span = Span { - expn_id: self.cx.codemap().record_expansion(ExpnInfo { - call_site: span, - callee: NameAndSpan { - format: MacroAttribute(pretty_name), - span: None, - allow_internal_unstable: false, - }, - }), - ..span - }; + invoc.expansion_data.mark.set_expn_info(expn_info); + let span = Span { ctxt: self.cx.backtrace(), ..span }; let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this name: keywords::Invalid.name(), span: DUMMY_SP, node: ast::MetaItemKind::Word, }; - return kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item)); + kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item)) } SyntaxExtension::BuiltinDerive(func) => { - let span = Span { - expn_id: self.cx.codemap().record_expansion(ExpnInfo { - call_site: span, - callee: NameAndSpan { - format: MacroAttribute(pretty_name), - span: None, - allow_internal_unstable: true, - }, - }), - ..span - }; + expn_info.callee.allow_internal_unstable = true; + invoc.expansion_data.mark.set_expn_info(expn_info); + let span = Span { ctxt: self.cx.backtrace(), ..span }; let mut items = Vec::new(); func(self.cx, span, &attr.meta().unwrap(), &item, &mut |a| items.push(a)); - return kind.expect_from_annotatables(items); + kind.expect_from_annotatables(items) } _ => { let msg = &format!("macro `{}` may not be used for derive attributes", attr.path); @@ -753,10 +737,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { // Detect use of feature-gated or invalid attributes on macro invocations // since they will not be detected after macro expansion. fn check_attributes(&mut self, attrs: &[ast::Attribute]) { - let codemap = &self.cx.parse_sess.codemap(); let features = self.cx.ecfg.features.unwrap(); for attr in attrs.iter() { - feature_gate::check_attribute(&attr, &self.cx.parse_sess, codemap, features); + feature_gate::check_attribute(&attr, &self.cx.parse_sess, features); } } } @@ -1065,23 +1048,21 @@ impl<'feat> ExpansionConfig<'feat> { } } -// A Marker adds the given mark to the syntax context and -// sets spans' `expn_id` to the given expn_id (unless it is `None`). -struct Marker { mark: Mark, expn_id: Option } +// A Marker adds the given mark to the syntax context. +struct Marker(Mark); impl Folder for Marker { fn fold_ident(&mut self, mut ident: Ident) -> Ident { - ident.ctxt = ident.ctxt.apply_mark(self.mark); + ident.ctxt = ident.ctxt.apply_mark(self.0); ident } - fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { - noop_fold_mac(mac, self) - } fn new_span(&mut self, mut span: Span) -> Span { - if let Some(expn_id) = self.expn_id { - span.expn_id = expn_id; - } + span.ctxt = span.ctxt.apply_mark(self.0); span } + + fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { + noop_fold_mac(mac, self) + } } diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 39b92c7d007..0103d6ea959 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -185,7 +185,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::Toke fn res_rel_file(cx: &mut ExtCtxt, sp: syntax_pos::Span, arg: &Path) -> PathBuf { // NB: relative paths are resolved relative to the compilation unit if !arg.is_absolute() { - let callsite = cx.codemap().source_callsite(sp); + let callsite = sp.source_callsite(); let mut cu = PathBuf::from(&cx.codemap().span_to_filename(callsite)); cu.pop(); cu.push(arg); diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index d56859d805c..12e746e024d 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -34,17 +34,19 @@ impl Delimited { } pub fn open_tt(&self, span: Span) -> TokenTree { - let open_span = match span { - DUMMY_SP => DUMMY_SP, - _ => Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span }, + let open_span = if span == DUMMY_SP { + DUMMY_SP + } else { + Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span } }; TokenTree::Token(open_span, self.open_token()) } pub fn close_tt(&self, span: Span) -> TokenTree { - let close_span = match span { - DUMMY_SP => DUMMY_SP, - _ => Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span }, + let close_span = if span == DUMMY_SP { + DUMMY_SP + } else { + Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span } }; TokenTree::Token(close_span, self.close_token()) } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9d280a413e6..12d25ca4274 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -28,7 +28,7 @@ use self::AttributeGate::*; use abi::Abi; use ast::{self, NodeId, PatKind, RangeEnd}; use attr; -use codemap::{CodeMap, Spanned}; +use codemap::Spanned; use syntax_pos::Span; use errors::{DiagnosticBuilder, Handler, FatalError}; use visit::{self, FnKind, Visitor}; @@ -831,7 +831,7 @@ impl GatedCfg { pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) { let (cfg, feature, has_feature) = GATED_CFGS[self.index]; - if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) { + if !has_feature(features) && !self.span.allows_unstable() { let explain = format!("`cfg({})` is experimental and subject to change", cfg); emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain); } @@ -841,7 +841,6 @@ impl GatedCfg { struct Context<'a> { features: &'a Features, parse_sess: &'a ParseSess, - cm: &'a CodeMap, plugin_attributes: &'a [(String, AttributeType)], } @@ -850,7 +849,7 @@ macro_rules! gate_feature_fn { let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain); let has_feature: bool = has_feature(&$cx.features); debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature); - if !has_feature && !cx.cm.span_allows_unstable(span) { + if !has_feature && !span.allows_unstable() { emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain); } }} @@ -908,12 +907,8 @@ impl<'a> Context<'a> { } } -pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, - cm: &CodeMap, features: &Features) { - let cx = Context { - features: features, parse_sess: parse_sess, - cm: cm, plugin_attributes: &[] - }; +pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) { + let cx = Context { features: features, parse_sess: parse_sess, plugin_attributes: &[] }; cx.check_attribute(attr, true); } @@ -1016,7 +1011,7 @@ struct PostExpansionVisitor<'a> { macro_rules! gate_feature_post { ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{ let (cx, span) = ($cx, $span); - if !cx.context.cm.span_allows_unstable(span) { + if !span.allows_unstable() { gate_feature!(cx.context, $feature, span, $explain) } }} @@ -1096,7 +1091,7 @@ fn starts_with_digit(s: &str) -> bool { impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_attribute(&mut self, attr: &ast::Attribute) { - if !self.context.cm.span_allows_unstable(attr.span) { + if !attr.span.allows_unstable() { // check for gated attributes self.context.check_attribute(attr, false); } @@ -1530,7 +1525,6 @@ pub fn check_crate(krate: &ast::Crate, let ctx = Context { features: features, parse_sess: sess, - cm: sess.codemap(), plugin_attributes: plugin_attributes, }; visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate); diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index fd762552248..dec1b7d1d87 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -202,7 +202,7 @@ impl DiagnosticSpan { // backtrace ourselves, but the `macro_backtrace` helper makes // some decision, such as dropping some frames, and I don't // want to duplicate that logic here. - let backtrace = je.cm.macro_backtrace(span).into_iter(); + let backtrace = span.macro_backtrace().into_iter(); DiagnosticSpan::from_span_full(span, is_primary, label, diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 6c975f3fc40..86ee1c5336d 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -125,7 +125,7 @@ pub mod ptr; pub mod show_span; pub mod std_inject; pub mod str; -pub mod symbol; +pub use syntax_pos::symbol; pub mod test; pub mod tokenstream; pub mod visit; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 43a9d8c5f78..e9eb4fbcc91 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5036,11 +5036,7 @@ impl<'a> Parser<'a> { the path:", path); self.expect(&token::CloseDelim(token::Paren))?; // `)` - let sp = Span { - lo: start_span.lo, - hi: self.prev_span.hi, - expn_id: start_span.expn_id, - }; + let sp = start_span.to(self.prev_span); let mut err = self.span_fatal_help(sp, &msg, &suggestion); err.span_suggestion(path_span, &help_msg, format!("in {}", path)); err.emit(); // emit diagnostic, but continue with public visibility diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index c541df9230a..c7820a15fb3 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -10,29 +10,27 @@ use ast; use attr; +use ext::hygiene::{Mark, SyntaxContext}; use symbol::{Symbol, keywords}; use syntax_pos::{DUMMY_SP, Span}; use codemap::{self, ExpnInfo, NameAndSpan, MacroAttribute}; -use parse::ParseSess; use ptr::P; use tokenstream::TokenStream; /// Craft a span that will be ignored by the stability lint's /// call to codemap's is_internal check. /// The expanded code uses the unstable `#[prelude_import]` attribute. -fn ignored_span(sess: &ParseSess, sp: Span) -> Span { - let info = ExpnInfo { +fn ignored_span(sp: Span) -> Span { + let mark = Mark::fresh(); + mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, callee: NameAndSpan { format: MacroAttribute(Symbol::intern("std_inject")), span: None, allow_internal_unstable: true, } - }; - let expn_id = sess.codemap().record_expansion(info); - let mut sp = sp; - sp.expn_id = expn_id; - return sp; + }); + Span { ctxt: SyntaxContext::empty().apply_mark(mark), ..sp } } pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> { @@ -45,10 +43,7 @@ pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> { } } -pub fn maybe_inject_crates_ref(sess: &ParseSess, - mut krate: ast::Crate, - alt_std_name: Option) - -> ast::Crate { +pub fn maybe_inject_crates_ref(mut krate: ast::Crate, alt_std_name: Option) -> ast::Crate { let name = match injected_crate_name(&krate) { Some(name) => name, None => return krate, @@ -67,7 +62,7 @@ pub fn maybe_inject_crates_ref(sess: &ParseSess, span: DUMMY_SP, })); - let span = ignored_span(sess, DUMMY_SP); + let span = ignored_span(DUMMY_SP); krate.module.items.insert(0, P(ast::Item { attrs: vec![ast::Attribute { style: ast::AttrStyle::Outer, diff --git a/src/libsyntax/symbol.rs b/src/libsyntax/symbol.rs deleted file mode 100644 index 2acbeee426b..00000000000 --- a/src/libsyntax/symbol.rs +++ /dev/null @@ -1,342 +0,0 @@ -// 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. - -//! An "interner" is a data structure that associates values with usize tags and -//! allows bidirectional lookup; i.e. given a value, one can easily find the -//! type, and vice versa. - -use serialize::{Decodable, Decoder, Encodable, Encoder}; -use std::cell::RefCell; -use std::collections::HashMap; -use std::fmt; - -/// A symbol is an interned or gensymed string. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Symbol(u32); - -// The interner in thread-local, so `Symbol` shouldn't move between threads. -impl !Send for Symbol { } - -impl Symbol { - /// Maps a string to its interned representation. - pub fn intern(string: &str) -> Self { - with_interner(|interner| interner.intern(string)) - } - - /// gensym's a new usize, using the current interner. - pub fn gensym(string: &str) -> Self { - with_interner(|interner| interner.gensym(string)) - } - - pub fn as_str(self) -> InternedString { - with_interner(|interner| unsafe { - InternedString { - string: ::std::mem::transmute::<&str, &str>(interner.get(self)) - } - }) - } - - pub fn as_u32(self) -> u32 { - self.0 - } -} - -impl fmt::Debug for Symbol { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}({})", self, self.0) - } -} - -impl fmt::Display for Symbol { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.as_str(), f) - } -} - -impl Encodable for Symbol { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_str(&self.as_str()) - } -} - -impl Decodable for Symbol { - fn decode(d: &mut D) -> Result { - Ok(Symbol::intern(&d.read_str()?)) - } -} - -impl> PartialEq for Symbol { - fn eq(&self, other: &T) -> bool { - self.as_str() == other.deref() - } -} - -#[derive(Default)] -pub struct Interner { - names: HashMap, Symbol>, - strings: Vec>, -} - -impl Interner { - pub fn new() -> Self { - Interner::default() - } - - fn prefill(init: &[&str]) -> Self { - let mut this = Interner::new(); - for &string in init { - this.intern(string); - } - this - } - - pub fn intern(&mut self, string: &str) -> Symbol { - if let Some(&name) = self.names.get(string) { - return name; - } - - let name = Symbol(self.strings.len() as u32); - let string = string.to_string().into_boxed_str(); - self.strings.push(string.clone()); - self.names.insert(string, name); - name - } - - fn gensym(&mut self, string: &str) -> Symbol { - let gensym = Symbol(self.strings.len() as u32); - // leave out of `names` to avoid colliding - self.strings.push(string.to_string().into_boxed_str()); - gensym - } - - pub fn get(&self, name: Symbol) -> &str { - &self.strings[name.0 as usize] - } -} - -// In this macro, there is the requirement that the name (the number) must be monotonically -// increasing by one in the special identifiers, starting at 0; the same holds for the keywords, -// except starting from the next number instead of zero. -macro_rules! declare_keywords {( - $( ($index: expr, $konst: ident, $string: expr) )* -) => { - pub mod keywords { - use ast; - #[derive(Clone, Copy, PartialEq, Eq)] - pub struct Keyword { - ident: ast::Ident, - } - impl Keyword { - #[inline] pub fn ident(self) -> ast::Ident { self.ident } - #[inline] pub fn name(self) -> ast::Name { self.ident.name } - } - $( - #[allow(non_upper_case_globals)] - pub const $konst: Keyword = Keyword { - ident: ast::Ident::with_empty_ctxt(super::Symbol($index)) - }; - )* - } - - impl Interner { - fn fresh() -> Self { - Interner::prefill(&[$($string,)*]) - } - } -}} - -// NB: leaving holes in the ident table is bad! a different ident will get -// interned with the id from the hole, but it will be between the min and max -// of the reserved words, and thus tagged as "reserved". -// After modifying this list adjust `is_strict_keyword`/`is_reserved_keyword`, -// this should be rarely necessary though if the keywords are kept in alphabetic order. -declare_keywords! { - // Invalid identifier - (0, Invalid, "") - - // Strict keywords used in the language. - (1, As, "as") - (2, Box, "box") - (3, Break, "break") - (4, Const, "const") - (5, Continue, "continue") - (6, Crate, "crate") - (7, Else, "else") - (8, Enum, "enum") - (9, Extern, "extern") - (10, False, "false") - (11, Fn, "fn") - (12, For, "for") - (13, If, "if") - (14, Impl, "impl") - (15, In, "in") - (16, Let, "let") - (17, Loop, "loop") - (18, Match, "match") - (19, Mod, "mod") - (20, Move, "move") - (21, Mut, "mut") - (22, Pub, "pub") - (23, Ref, "ref") - (24, Return, "return") - (25, SelfValue, "self") - (26, SelfType, "Self") - (27, Static, "static") - (28, Struct, "struct") - (29, Super, "super") - (30, Trait, "trait") - (31, True, "true") - (32, Type, "type") - (33, Unsafe, "unsafe") - (34, Use, "use") - (35, Where, "where") - (36, While, "while") - - // Keywords reserved for future use. - (37, Abstract, "abstract") - (38, Alignof, "alignof") - (39, Become, "become") - (40, Do, "do") - (41, Final, "final") - (42, Macro, "macro") - (43, Offsetof, "offsetof") - (44, Override, "override") - (45, Priv, "priv") - (46, Proc, "proc") - (47, Pure, "pure") - (48, Sizeof, "sizeof") - (49, Typeof, "typeof") - (50, Unsized, "unsized") - (51, Virtual, "virtual") - (52, Yield, "yield") - - // Weak keywords, have special meaning only in specific contexts. - (53, Default, "default") - (54, StaticLifetime, "'static") - (55, Union, "union") - (56, Catch, "catch") - - // A virtual keyword that resolves to the crate root when used in a lexical scope. - (57, CrateRoot, "{{root}}") -} - -// If an interner exists in TLS, return it. Otherwise, prepare a fresh one. -fn with_interner T>(f: F) -> T { - thread_local!(static INTERNER: RefCell = { - RefCell::new(Interner::fresh()) - }); - INTERNER.with(|interner| f(&mut *interner.borrow_mut())) -} - -/// Represents a string stored in the thread-local interner. Because the -/// interner lives for the life of the thread, this can be safely treated as an -/// immortal string, as long as it never crosses between threads. -/// -/// FIXME(pcwalton): You must be careful about what you do in the destructors -/// of objects stored in TLS, because they may run after the interner is -/// destroyed. In particular, they must not access string contents. This can -/// be fixed in the future by just leaking all strings until thread death -/// somehow. -#[derive(Clone, Hash, PartialOrd, Eq, Ord)] -pub struct InternedString { - string: &'static str, -} - -impl ::std::convert::AsRef for InternedString where str: ::std::convert::AsRef { - fn as_ref(&self) -> &U { - self.string.as_ref() - } -} - -impl> ::std::cmp::PartialEq for InternedString { - fn eq(&self, other: &T) -> bool { - self.string == other.deref() - } -} - -impl ::std::cmp::PartialEq for str { - fn eq(&self, other: &InternedString) -> bool { - self == other.string - } -} - -impl<'a> ::std::cmp::PartialEq for &'a str { - fn eq(&self, other: &InternedString) -> bool { - *self == other.string - } -} - -impl ::std::cmp::PartialEq for String { - fn eq(&self, other: &InternedString) -> bool { - self == other.string - } -} - -impl<'a> ::std::cmp::PartialEq for &'a String { - fn eq(&self, other: &InternedString) -> bool { - *self == other.string - } -} - -impl !Send for InternedString { } - -impl ::std::ops::Deref for InternedString { - type Target = str; - fn deref(&self) -> &str { self.string } -} - -impl fmt::Debug for InternedString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self.string, f) - } -} - -impl fmt::Display for InternedString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self.string, f) - } -} - -impl Decodable for InternedString { - fn decode(d: &mut D) -> Result { - Ok(Symbol::intern(&d.read_str()?).as_str()) - } -} - -impl Encodable for InternedString { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_str(self.string) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn interner_tests() { - let mut i: Interner = Interner::new(); - // first one is zero: - assert_eq!(i.intern("dog"), Symbol(0)); - // re-use gets the same entry: - assert_eq!(i.intern ("dog"), Symbol(0)); - // different string gets a different #: - assert_eq!(i.intern("cat"), Symbol(1)); - assert_eq!(i.intern("cat"), Symbol(1)); - // dog is still at zero - assert_eq!(i.intern("dog"), Symbol(0)); - // gensym gets 3 - assert_eq!(i.gensym("zebra"), Symbol(2)); - // gensym of same string gets new number : - assert_eq!(i.gensym("zebra"), Symbol(3)); - // gensym of *existing* string gets new number: - assert_eq!(i.gensym("dog"), Symbol(4)); - } -} diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 6fb6db9ca02..50380626d7f 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -31,6 +31,7 @@ use entry::{self, EntryPointType}; use ext::base::{ExtCtxt, Resolver}; use ext::build::AstBuilder; use ext::expand::ExpansionConfig; +use ext::hygiene::{Mark, SyntaxContext}; use fold::Folder; use util::move_map::MoveMap; use fold; @@ -62,6 +63,7 @@ struct TestCtxt<'a> { testfns: Vec, reexport_test_harness_main: Option, is_test_crate: bool, + ctxt: SyntaxContext, // top-level re-export submodule, filled out after folding is finished toplevel_reexport: Option, @@ -275,6 +277,7 @@ fn generate_test_harness(sess: &ParseSess, let mut cleaner = EntryPointCleaner { depth: 0 }; let krate = cleaner.fold_crate(krate); + let mark = Mark::fresh(); let mut cx: TestCtxt = TestCtxt { sess: sess, span_diagnostic: sd, @@ -284,15 +287,16 @@ fn generate_test_harness(sess: &ParseSess, reexport_test_harness_main: reexport_test_harness_main, is_test_crate: is_test_crate(&krate), toplevel_reexport: None, + ctxt: SyntaxContext::empty().apply_mark(mark), }; cx.ext_cx.crate_root = Some("std"); - cx.ext_cx.bt_push(ExpnInfo { + mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, callee: NameAndSpan { format: MacroAttribute(Symbol::intern("test")), span: None, - allow_internal_unstable: false, + allow_internal_unstable: true, } }); @@ -307,18 +311,7 @@ fn generate_test_harness(sess: &ParseSess, /// call to codemap's is_internal check. /// The expanded code calls some unstable functions in the test crate. fn ignored_span(cx: &TestCtxt, sp: Span) -> Span { - let info = ExpnInfo { - call_site: sp, - callee: NameAndSpan { - format: MacroAttribute(Symbol::intern("test")), - span: None, - allow_internal_unstable: true, - } - }; - let expn_id = cx.sess.codemap().record_expansion(info); - let mut sp = sp; - sp.expn_id = expn_id; - return sp; + Span { ctxt: cx.ctxt, ..sp } } #[derive(PartialEq)] diff --git a/src/libsyntax/test_snippet.rs b/src/libsyntax/test_snippet.rs index c6d6e6237f2..c537a0ee166 100644 --- a/src/libsyntax/test_snippet.rs +++ b/src/libsyntax/test_snippet.rs @@ -83,7 +83,7 @@ fn make_span(file_text: &str, start: &Position, end: &Position) -> Span { Span { lo: BytePos(start as u32), hi: BytePos(end as u32), - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, } } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index b75b3efda36..86bfdebe42b 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -56,18 +56,20 @@ impl Delimited { /// Returns the opening delimiter as a token tree. pub fn open_tt(&self, span: Span) -> TokenTree { - let open_span = match span { - DUMMY_SP => DUMMY_SP, - _ => Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span }, + let open_span = if span == DUMMY_SP { + DUMMY_SP + } else { + Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span } }; TokenTree::Token(open_span, self.open_token()) } /// Returns the closing delimiter as a token tree. pub fn close_tt(&self, span: Span) -> TokenTree { - let close_span = match span { - DUMMY_SP => DUMMY_SP, - _ => Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span }, + let close_span = if span == DUMMY_SP { + DUMMY_SP + } else { + Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span } }; TokenTree::Token(close_span, self.close_token()) } @@ -425,7 +427,7 @@ mod tests { Span { lo: BytePos(a), hi: BytePos(b), - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, } } diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index 767ec94a0ce..923e8072f43 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -13,7 +13,6 @@ use self::State::*; use syntax::ast; -use syntax::codemap; use syntax::ext::base; use syntax::ext::base::*; use syntax::feature_gate; @@ -240,15 +239,6 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, } } - let expn_id = cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: sp, - callee: codemap::NameAndSpan { - format: codemap::MacroBang(Symbol::intern("asm")), - span: None, - allow_internal_unstable: false, - }, - }); - MacEager::expr(P(ast::Expr { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::InlineAsm(P(ast::InlineAsm { @@ -260,7 +250,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, volatile: volatile, alignstack: alignstack, dialect: dialect, - expn_id: expn_id, + ctxt: cx.backtrace(), })), span: sp, attrs: ast::ThinVec::new(), diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index d14b59d6c70..1993d6ebe5b 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -111,7 +111,7 @@ fn cs_clone_shallow(name: &str, ty: P, span: Span, helper_name: &str) { // Generate statement `let _: helper_name;`, // set the expn ID so we can use the unstable struct. - let span = super::allow_unstable(cx, span, "derive(Clone)"); + let span = Span { ctxt: cx.backtrace(), ..span}; let assert_path = cx.path_all(span, true, cx.std_path(&["clone", helper_name]), vec![], vec![ty], vec![]); diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs index 6ab5987a159..eef21492deb 100644 --- a/src/libsyntax_ext/deriving/cmp/eq.rs +++ b/src/libsyntax_ext/deriving/cmp/eq.rs @@ -58,7 +58,7 @@ fn cs_total_eq_assert(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) ty: P, span: Span, helper_name: &str) { // Generate statement `let _: helper_name;`, // set the expn ID so we can use the unstable struct. - let span = super::allow_unstable(cx, span, "derive(Eq)"); + let span = Span { ctxt: cx.backtrace(), ..span }; let assert_path = cx.path_all(span, true, cx.std_path(&["cmp", helper_name]), vec![], vec![ty], vec![]); diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index a767716466c..ec4cb815960 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -66,8 +66,8 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`"), }; - // We want to make sure we have the expn_id set so that we can use unstable methods - let span = Span { expn_id: cx.backtrace(), ..span }; + // We want to make sure we have the ctxt set so that we can use unstable methods + let span = Span { ctxt: cx.backtrace(), ..span }; let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked)); let builder = Ident::from_str("builder"); let builder_expr = cx.expr_ident(span, builder.clone()); diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 48e7ff0d243..1ff0fec1c96 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -375,7 +375,7 @@ fn find_type_parameters(ty: &ast::Ty, } fn visit_mac(&mut self, mac: &ast::Mac) { - let span = Span { expn_id: self.span.expn_id, ..mac.span }; + let span = Span { ctxt: self.span.ctxt, ..mac.span }; self.cx.span_err(span, "`derive` cannot be used on items with type macros"); } } @@ -1458,7 +1458,7 @@ impl<'a> MethodDef<'a> { .iter() .map(|v| { let ident = v.node.name; - let sp = Span { expn_id: trait_.span.expn_id, ..v.span }; + let sp = Span { ctxt: trait_.span.ctxt, ..v.span }; let summary = trait_.summarise_struct(cx, &v.node.data); (ident, sp, summary) }) @@ -1478,7 +1478,7 @@ impl<'a> TraitDef<'a> { let mut named_idents = Vec::new(); let mut just_spans = Vec::new(); for field in struct_def.fields() { - let sp = Span { expn_id: self.span.expn_id, ..field.span }; + let sp = Span { ctxt: self.span.ctxt, ..field.span }; match field.ident { Some(ident) => named_idents.push((ident, sp)), _ => just_spans.push(sp), @@ -1523,7 +1523,7 @@ impl<'a> TraitDef<'a> { let mut paths = Vec::new(); let mut ident_exprs = Vec::new(); for (i, struct_field) in struct_def.fields().iter().enumerate() { - let sp = Span { expn_id: self.span.expn_id, ..struct_field.span }; + let sp = Span { ctxt: self.span.ctxt, ..struct_field.span }; let ident = cx.ident_of(&format!("{}_{}", prefix, i)); paths.push(codemap::Spanned { span: sp, @@ -1544,7 +1544,7 @@ impl<'a> TraitDef<'a> { cx.span_bug(sp, "a braced struct with unnamed fields in `derive`"); } codemap::Spanned { - span: Span { expn_id: self.span.expn_id, ..pat.span }, + span: Span { ctxt: self.span.ctxt, ..pat.span }, node: ast::FieldPat { ident: ident.unwrap(), pat: pat, @@ -1576,7 +1576,7 @@ impl<'a> TraitDef<'a> { mutbl: ast::Mutability) -> (P, Vec<(Span, Option, P, &'a [ast::Attribute])>) { let variant_ident = variant.node.name; - let sp = Span { expn_id: self.span.expn_id, ..variant.span }; + let sp = Span { ctxt: self.span.ctxt, ..variant.span }; let variant_path = cx.path(sp, vec![enum_ident, variant_ident]); self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl) } diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index b51591bf89d..b2bb43e41ed 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -12,9 +12,9 @@ use std::rc::Rc; use syntax::ast; -use syntax::codemap; use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver}; use syntax::ext::build::AstBuilder; +use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::ptr::P; use syntax::symbol::Symbol; use syntax_pos::Span; @@ -74,20 +74,6 @@ pub mod ord; pub mod generic; -fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span { - Span { - expn_id: cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: span, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(Symbol::intern(attr_name)), - span: Some(span), - allow_internal_unstable: true, - }, - }), - ..span - } -} - macro_rules! derive_traits { ($( $name:expr => $func:path, )+) => { pub fn is_builtin_trait(name: ast::Name) -> bool { @@ -177,15 +163,15 @@ fn call_intrinsic(cx: &ExtCtxt, intrinsic: &str, args: Vec>) -> P { - span.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: span, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(Symbol::intern("derive")), - span: Some(span), - allow_internal_unstable: true, - }, - }); - + if cx.current_expansion.mark.expn_info().unwrap().callee.allow_internal_unstable { + span.ctxt = cx.backtrace(); + } else { // Avoid instability errors with user defined curstom derives, cc #36316 + let mut info = cx.current_expansion.mark.expn_info().unwrap(); + info.callee.allow_internal_unstable = true; + let mark = Mark::fresh(); + mark.set_expn_info(info); + span.ctxt = SyntaxContext::empty().apply_mark(mark); + } let path = cx.std_path(&["intrinsics", intrinsic]); let call = cx.expr_call_global(span, path, args); diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index d2afa08cada..aeb5b1e0a53 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -641,10 +641,11 @@ impl<'a, 'b> Context<'a, 'b> { fn format_arg(ecx: &ExtCtxt, macsp: Span, - sp: Span, + mut sp: Span, ty: &ArgumentType, arg: P) -> P { + sp.ctxt = sp.ctxt.apply_mark(ecx.current_expansion.mark); let trait_ = match *ty { Placeholder(ref tyname) => { match &tyname[..] { diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index 2d815b3f1bb..bb89caab709 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -17,6 +17,7 @@ use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute}; use syntax::ext::base::ExtCtxt; use syntax::ext::build::AstBuilder; use syntax::ext::expand::ExpansionConfig; +use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::fold::Folder; use syntax::parse::ParseSess; use syntax::ptr::P; @@ -360,7 +361,8 @@ fn mk_registrar(cx: &mut ExtCtxt, custom_derives: &[ProcMacroDerive], custom_attrs: &[ProcMacroDef], custom_macros: &[ProcMacroDef]) -> P { - let eid = cx.codemap().record_expansion(ExpnInfo { + let mark = Mark::fresh(); + mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, callee: NameAndSpan { format: MacroAttribute(Symbol::intern("proc_macro")), @@ -368,7 +370,7 @@ fn mk_registrar(cx: &mut ExtCtxt, allow_internal_unstable: true, } }); - let span = Span { expn_id: eid, ..DUMMY_SP }; + let span = Span { ctxt: SyntaxContext::empty().apply_mark(mark), ..DUMMY_SP }; let proc_macro = Ident::from_str("proc_macro"); let krate = cx.item(span, diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index feebbcd6f03..8a9ff647b3e 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -15,12 +15,16 @@ //! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216. //! DOI=10.1017/S0956796812000093 http://dx.doi.org/10.1017/S0956796812000093 +use Span; +use symbol::Symbol; + +use serialize::{Encodable, Decodable, Encoder, Decoder}; use std::cell::RefCell; use std::collections::HashMap; use std::fmt; /// A SyntaxContext represents a chain of macro expansions (represented by marks). -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Default)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SyntaxContext(u32); #[derive(Copy, Clone)] @@ -36,8 +40,8 @@ pub struct Mark(u32); impl Mark { pub fn fresh() -> Self { HygieneData::with(|data| { - let next_mark = Mark(data.next_mark.0 + 1); - ::std::mem::replace(&mut data.next_mark, next_mark) + data.marks.push(None); + Mark(data.marks.len() as u32 - 1) }) } @@ -53,23 +57,31 @@ impl Mark { pub fn from_u32(raw: u32) -> Mark { Mark(raw) } + + pub fn expn_info(self) -> Option { + HygieneData::with(|data| data.marks[self.0 as usize].clone()) + } + + pub fn set_expn_info(self, info: ExpnInfo) { + HygieneData::with(|data| data.marks[self.0 as usize] = Some(info)) + } } struct HygieneData { + marks: Vec>, syntax_contexts: Vec, markings: HashMap<(SyntaxContext, Mark), SyntaxContext>, - next_mark: Mark, } impl HygieneData { fn new() -> Self { HygieneData { + marks: vec![None], syntax_contexts: vec![SyntaxContextData { outer_mark: Mark::root(), prev_ctxt: SyntaxContext::empty(), }], markings: HashMap::new(), - next_mark: Mark(1), } } @@ -81,8 +93,8 @@ impl HygieneData { } } -pub fn reset_hygiene_data() { - HygieneData::with(|data| *data = HygieneData::new()) +pub fn clear_markings() { + HygieneData::with(|data| data.markings = HashMap::new()); } impl SyntaxContext { @@ -113,6 +125,10 @@ impl SyntaxContext { }) }) } + + pub fn outer(self) -> Mark { + HygieneData::with(|data| data.syntax_contexts[self.0 as usize].outer_mark) + } } impl fmt::Debug for SyntaxContext { @@ -120,3 +136,67 @@ impl fmt::Debug for SyntaxContext { write!(f, "#{}", self.0) } } + +/// Extra information for tracking spans of macro and syntax sugar expansion +#[derive(Clone, Hash, Debug)] +pub struct ExpnInfo { + /// The location of the actual macro invocation or syntax sugar , e.g. + /// `let x = foo!();` or `if let Some(y) = x {}` + /// + /// This may recursively refer to other macro invocations, e.g. if + /// `foo!()` invoked `bar!()` internally, and there was an + /// expression inside `bar!`; the call_site of the expression in + /// the expansion would point to the `bar!` invocation; that + /// call_site span would have its own ExpnInfo, with the call_site + /// pointing to the `foo!` invocation. + pub call_site: Span, + /// Information about the expansion. + pub callee: NameAndSpan +} + +#[derive(Clone, Hash, Debug)] +pub struct NameAndSpan { + /// The format with which the macro was invoked. + pub format: ExpnFormat, + /// Whether the macro is allowed to use #[unstable]/feature-gated + /// features internally without forcing the whole crate to opt-in + /// to them. + pub allow_internal_unstable: bool, + /// The span of the macro definition itself. The macro may not + /// have a sensible definition span (e.g. something defined + /// completely inside libsyntax) in which case this is None. + pub span: Option +} + +impl NameAndSpan { + pub fn name(&self) -> Symbol { + match self.format { + ExpnFormat::MacroAttribute(s) | + ExpnFormat::MacroBang(s) | + ExpnFormat::CompilerDesugaring(s) => s, + } + } +} + +/// The source of expansion. +#[derive(Clone, Hash, Debug, PartialEq, Eq)] +pub enum ExpnFormat { + /// e.g. #[derive(...)] + MacroAttribute(Symbol), + /// e.g. `format!()` + MacroBang(Symbol), + /// Desugaring done by the compiler during HIR lowering. + CompilerDesugaring(Symbol) +} + +impl Encodable for SyntaxContext { + fn encode(&self, _: &mut E) -> Result<(), E::Error> { + Ok(()) // FIXME(jseyfried) intercrate hygiene + } +} + +impl Decodable for SyntaxContext { + fn decode(_: &mut D) -> Result { + Ok(SyntaxContext::empty()) // FIXME(jseyfried) intercrate hygiene + } +} diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 1b62d62348b..9b45e364ecf 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -25,6 +25,7 @@ #![feature(const_fn)] #![feature(custom_attribute)] +#![feature(optin_builtin_traits)] #![allow(unused_attributes)] #![feature(rustc_private)] #![feature(staged_api)] @@ -43,6 +44,9 @@ extern crate serialize; extern crate serialize as rustc_serialize; // used by deriving pub mod hygiene; +pub use hygiene::{SyntaxContext, ExpnInfo, ExpnFormat, NameAndSpan}; + +pub mod symbol; pub type FileName = String; @@ -60,7 +64,7 @@ pub struct Span { pub hi: BytePos, /// Information about where the macro came from, if this piece of /// code was created by a macro expansion. - pub expn_id: ExpnId + pub ctxt: SyntaxContext, } /// A collection of spans. Spans have two orthogonal attributes: @@ -79,7 +83,7 @@ impl Span { /// Returns a new span representing just the end-point of this span pub fn end_point(self) -> Span { let lo = cmp::max(self.hi.0 - 1, self.lo.0); - Span { lo: BytePos(lo), hi: self.hi, expn_id: self.expn_id} + Span { lo: BytePos(lo), hi: self.hi, ctxt: self.ctxt } } /// Returns `self` if `self` is not the dummy span, and `other` otherwise. @@ -107,6 +111,69 @@ impl Span { None } } + + /// Return the source span - this is either the supplied span, or the span for + /// the macro callsite that expanded to it. + pub fn source_callsite(self) -> Span { + self.ctxt.outer().expn_info().map(|info| info.call_site.source_callsite()).unwrap_or(self) + } + + /// Return the source callee. + /// + /// Returns None if the supplied span has no expansion trace, + /// else returns the NameAndSpan for the macro definition + /// corresponding to the source callsite. + pub fn source_callee(self) -> Option { + fn source_callee(info: ExpnInfo) -> NameAndSpan { + match info.call_site.ctxt.outer().expn_info() { + Some(info) => source_callee(info), + None => info.callee, + } + } + self.ctxt.outer().expn_info().map(source_callee) + } + + /// Check if a span is "internal" to a macro in which #[unstable] + /// items can be used (that is, a macro marked with + /// `#[allow_internal_unstable]`). + pub fn allows_unstable(&self) -> bool { + match self.ctxt.outer().expn_info() { + Some(info) => info.callee.allow_internal_unstable, + None => false, + } + } + + pub fn macro_backtrace(mut self) -> Vec { + let mut prev_span = DUMMY_SP; + let mut result = vec![]; + loop { + let info = match self.ctxt.outer().expn_info() { + Some(info) => info, + None => break, + }; + + let (pre, post) = match info.callee.format { + ExpnFormat::MacroAttribute(..) => ("#[", "]"), + ExpnFormat::MacroBang(..) => ("", "!"), + ExpnFormat::CompilerDesugaring(..) => ("desugaring of `", "`"), + }; + let macro_decl_name = format!("{}{}{}", pre, info.callee.name(), post); + let def_site_span = info.callee.span; + + // Don't print recursive invocations + if !info.call_site.source_equal(&prev_span) { + result.push(MacroBacktrace { + call_site: info.call_site, + macro_decl_name: macro_decl_name, + def_site_span: def_site_span, + }); + } + + prev_span = self; + self = info.call_site; + } + result + } } #[derive(Clone, Debug)] @@ -147,8 +214,8 @@ impl serialize::UseSpecializedDecodable for Span { } fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Span {{ lo: {:?}, hi: {:?}, expn_id: {:?} }}", - span.lo, span.hi, span.expn_id) + write!(f, "Span {{ lo: {:?}, hi: {:?}, ctxt: {:?} }}", + span.lo, span.hi, span.ctxt) } impl fmt::Debug for Span { @@ -157,12 +224,7 @@ impl fmt::Debug for Span { } } -pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), expn_id: NO_EXPANSION }; - -// Generic span to be used for code originating from the command line -pub const COMMAND_LINE_SP: Span = Span { lo: BytePos(0), - hi: BytePos(0), - expn_id: COMMAND_LINE_EXPN }; +pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), ctxt: NO_EXPANSION }; impl MultiSpan { pub fn new() -> MultiSpan { @@ -256,22 +318,7 @@ impl From for MultiSpan { } } -#[derive(PartialEq, Eq, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Copy, Ord, PartialOrd)] -pub struct ExpnId(pub u32); - -pub const NO_EXPANSION: ExpnId = ExpnId(!0); -// For code appearing from the command line -pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(!1); - -impl ExpnId { - pub fn from_u32(id: u32) -> ExpnId { - ExpnId(id) - } - - pub fn into_u32(self) -> u32 { - self.0 - } -} +pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty(); /// Identifies an offset of a multi-byte character in a FileMap #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq)] @@ -651,7 +698,7 @@ thread_local!(pub static SPAN_DEBUG: Cell fmt:: /* assuming that we're not in macro expansion */ pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span { - Span {lo: lo, hi: hi, expn_id: NO_EXPANSION} + Span {lo: lo, hi: hi, ctxt: NO_EXPANSION} } pub struct MacroBacktrace { diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs new file mode 100644 index 00000000000..b866652c49f --- /dev/null +++ b/src/libsyntax_pos/symbol.rs @@ -0,0 +1,389 @@ +// 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. + +//! An "interner" is a data structure that associates values with usize tags and +//! allows bidirectional lookup; i.e. given a value, one can easily find the +//! type, and vice versa. + +use hygiene::SyntaxContext; + +use serialize::{Decodable, Decoder, Encodable, Encoder}; +use std::cell::RefCell; +use std::collections::HashMap; +use std::fmt; + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct Ident { + pub name: Symbol, + pub ctxt: SyntaxContext, +} + +impl Ident { + pub const fn with_empty_ctxt(name: Symbol) -> Ident { + Ident { name: name, ctxt: SyntaxContext::empty() } + } + + /// Maps a string to an identifier with an empty syntax context. + pub fn from_str(string: &str) -> Ident { + Ident::with_empty_ctxt(Symbol::intern(string)) + } + + pub fn unhygienize(self) -> Ident { + Ident { name: self.name, ctxt: SyntaxContext::empty() } + } +} + +impl fmt::Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}{:?}", self.name, self.ctxt) + } +} + +impl fmt::Display for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.name, f) + } +} + +impl Encodable for Ident { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + self.name.encode(s) + } +} + +impl Decodable for Ident { + fn decode(d: &mut D) -> Result { + Ok(Ident::with_empty_ctxt(Symbol::decode(d)?)) + } +} + +/// A symbol is an interned or gensymed string. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Symbol(u32); + +// The interner in thread-local, so `Symbol` shouldn't move between threads. +impl !Send for Symbol { } + +impl Symbol { + /// Maps a string to its interned representation. + pub fn intern(string: &str) -> Self { + with_interner(|interner| interner.intern(string)) + } + + /// gensym's a new usize, using the current interner. + pub fn gensym(string: &str) -> Self { + with_interner(|interner| interner.gensym(string)) + } + + pub fn as_str(self) -> InternedString { + with_interner(|interner| unsafe { + InternedString { + string: ::std::mem::transmute::<&str, &str>(interner.get(self)) + } + }) + } + + pub fn as_u32(self) -> u32 { + self.0 + } +} + +impl fmt::Debug for Symbol { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}({})", self, self.0) + } +} + +impl fmt::Display for Symbol { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.as_str(), f) + } +} + +impl Encodable for Symbol { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_str(&self.as_str()) + } +} + +impl Decodable for Symbol { + fn decode(d: &mut D) -> Result { + Ok(Symbol::intern(&d.read_str()?)) + } +} + +impl> PartialEq for Symbol { + fn eq(&self, other: &T) -> bool { + self.as_str() == other.deref() + } +} + +#[derive(Default)] +pub struct Interner { + names: HashMap, Symbol>, + strings: Vec>, +} + +impl Interner { + pub fn new() -> Self { + Interner::default() + } + + fn prefill(init: &[&str]) -> Self { + let mut this = Interner::new(); + for &string in init { + this.intern(string); + } + this + } + + pub fn intern(&mut self, string: &str) -> Symbol { + if let Some(&name) = self.names.get(string) { + return name; + } + + let name = Symbol(self.strings.len() as u32); + let string = string.to_string().into_boxed_str(); + self.strings.push(string.clone()); + self.names.insert(string, name); + name + } + + fn gensym(&mut self, string: &str) -> Symbol { + let gensym = Symbol(self.strings.len() as u32); + // leave out of `names` to avoid colliding + self.strings.push(string.to_string().into_boxed_str()); + gensym + } + + pub fn get(&self, name: Symbol) -> &str { + &self.strings[name.0 as usize] + } +} + +// In this macro, there is the requirement that the name (the number) must be monotonically +// increasing by one in the special identifiers, starting at 0; the same holds for the keywords, +// except starting from the next number instead of zero. +macro_rules! declare_keywords {( + $( ($index: expr, $konst: ident, $string: expr) )* +) => { + pub mod keywords { + use super::{Symbol, Ident}; + #[derive(Clone, Copy, PartialEq, Eq)] + pub struct Keyword { + ident: Ident, + } + impl Keyword { + #[inline] pub fn ident(self) -> Ident { self.ident } + #[inline] pub fn name(self) -> Symbol { self.ident.name } + } + $( + #[allow(non_upper_case_globals)] + pub const $konst: Keyword = Keyword { + ident: Ident::with_empty_ctxt(super::Symbol($index)) + }; + )* + } + + impl Interner { + fn fresh() -> Self { + Interner::prefill(&[$($string,)*]) + } + } +}} + +// NB: leaving holes in the ident table is bad! a different ident will get +// interned with the id from the hole, but it will be between the min and max +// of the reserved words, and thus tagged as "reserved". +// After modifying this list adjust `is_strict_keyword`/`is_reserved_keyword`, +// this should be rarely necessary though if the keywords are kept in alphabetic order. +declare_keywords! { + // Invalid identifier + (0, Invalid, "") + + // Strict keywords used in the language. + (1, As, "as") + (2, Box, "box") + (3, Break, "break") + (4, Const, "const") + (5, Continue, "continue") + (6, Crate, "crate") + (7, Else, "else") + (8, Enum, "enum") + (9, Extern, "extern") + (10, False, "false") + (11, Fn, "fn") + (12, For, "for") + (13, If, "if") + (14, Impl, "impl") + (15, In, "in") + (16, Let, "let") + (17, Loop, "loop") + (18, Match, "match") + (19, Mod, "mod") + (20, Move, "move") + (21, Mut, "mut") + (22, Pub, "pub") + (23, Ref, "ref") + (24, Return, "return") + (25, SelfValue, "self") + (26, SelfType, "Self") + (27, Static, "static") + (28, Struct, "struct") + (29, Super, "super") + (30, Trait, "trait") + (31, True, "true") + (32, Type, "type") + (33, Unsafe, "unsafe") + (34, Use, "use") + (35, Where, "where") + (36, While, "while") + + // Keywords reserved for future use. + (37, Abstract, "abstract") + (38, Alignof, "alignof") + (39, Become, "become") + (40, Do, "do") + (41, Final, "final") + (42, Macro, "macro") + (43, Offsetof, "offsetof") + (44, Override, "override") + (45, Priv, "priv") + (46, Proc, "proc") + (47, Pure, "pure") + (48, Sizeof, "sizeof") + (49, Typeof, "typeof") + (50, Unsized, "unsized") + (51, Virtual, "virtual") + (52, Yield, "yield") + + // Weak keywords, have special meaning only in specific contexts. + (53, Default, "default") + (54, StaticLifetime, "'static") + (55, Union, "union") + (56, Catch, "catch") + + // A virtual keyword that resolves to the crate root when used in a lexical scope. + (57, CrateRoot, "{{root}}") +} + +// If an interner exists in TLS, return it. Otherwise, prepare a fresh one. +fn with_interner T>(f: F) -> T { + thread_local!(static INTERNER: RefCell = { + RefCell::new(Interner::fresh()) + }); + INTERNER.with(|interner| f(&mut *interner.borrow_mut())) +} + +/// Represents a string stored in the thread-local interner. Because the +/// interner lives for the life of the thread, this can be safely treated as an +/// immortal string, as long as it never crosses between threads. +/// +/// FIXME(pcwalton): You must be careful about what you do in the destructors +/// of objects stored in TLS, because they may run after the interner is +/// destroyed. In particular, they must not access string contents. This can +/// be fixed in the future by just leaking all strings until thread death +/// somehow. +#[derive(Clone, Hash, PartialOrd, Eq, Ord)] +pub struct InternedString { + string: &'static str, +} + +impl ::std::convert::AsRef for InternedString where str: ::std::convert::AsRef { + fn as_ref(&self) -> &U { + self.string.as_ref() + } +} + +impl> ::std::cmp::PartialEq for InternedString { + fn eq(&self, other: &T) -> bool { + self.string == other.deref() + } +} + +impl ::std::cmp::PartialEq for str { + fn eq(&self, other: &InternedString) -> bool { + self == other.string + } +} + +impl<'a> ::std::cmp::PartialEq for &'a str { + fn eq(&self, other: &InternedString) -> bool { + *self == other.string + } +} + +impl ::std::cmp::PartialEq for String { + fn eq(&self, other: &InternedString) -> bool { + self == other.string + } +} + +impl<'a> ::std::cmp::PartialEq for &'a String { + fn eq(&self, other: &InternedString) -> bool { + *self == other.string + } +} + +impl !Send for InternedString { } + +impl ::std::ops::Deref for InternedString { + type Target = str; + fn deref(&self) -> &str { self.string } +} + +impl fmt::Debug for InternedString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self.string, f) + } +} + +impl fmt::Display for InternedString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self.string, f) + } +} + +impl Decodable for InternedString { + fn decode(d: &mut D) -> Result { + Ok(Symbol::intern(&d.read_str()?).as_str()) + } +} + +impl Encodable for InternedString { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_str(self.string) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn interner_tests() { + let mut i: Interner = Interner::new(); + // first one is zero: + assert_eq!(i.intern("dog"), Symbol(0)); + // re-use gets the same entry: + assert_eq!(i.intern ("dog"), Symbol(0)); + // different string gets a different #: + assert_eq!(i.intern("cat"), Symbol(1)); + assert_eq!(i.intern("cat"), Symbol(1)); + // dog is still at zero + assert_eq!(i.intern("dog"), Symbol(0)); + // gensym gets 3 + assert_eq!(i.gensym("zebra"), Symbol(2)); + // gensym of same string gets new number : + assert_eq!(i.gensym("zebra"), Symbol(3)); + // gensym of *existing* string gets new number: + assert_eq!(i.gensym("dog"), Symbol(4)); + } +} diff --git a/src/test/compile-fail-fulldeps/qquote.rs b/src/test/compile-fail-fulldeps/qquote.rs index bd25561065b..272bf1150ca 100644 --- a/src/test/compile-fail-fulldeps/qquote.rs +++ b/src/test/compile-fail-fulldeps/qquote.rs @@ -27,14 +27,6 @@ fn main() { &ps, syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), &mut resolver); - cx.bt_push(syntax::codemap::ExpnInfo { - call_site: DUMMY_SP, - callee: syntax::codemap::NameAndSpan { - format: syntax::codemap::MacroBang(Symbol::intern("")), - allow_internal_unstable: false, - span: None, - } - }); let cx = &mut cx; assert_eq!(pprust::expr_to_string(&*quote_expr!(&cx, 23)), "23"); diff --git a/src/test/run-fail-fulldeps/qquote.rs b/src/test/run-fail-fulldeps/qquote.rs index d692bb519c1..5518ab47c2b 100644 --- a/src/test/run-fail-fulldeps/qquote.rs +++ b/src/test/run-fail-fulldeps/qquote.rs @@ -30,14 +30,6 @@ fn main() { &ps, syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), &mut resolver); - cx.bt_push(syntax::codemap::ExpnInfo { - call_site: DUMMY_SP, - callee: syntax::codemap::NameAndSpan { - format: syntax::codemap::MacroBang(Symbol::intern("")), - allow_internal_unstable: false, - span: None, - } - }); let cx = &mut cx; println!("{}", pprust::expr_to_string(&*quote_expr!(&cx, 23))); diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs index b4ed57192cc..4a8246ec429 100644 --- a/src/test/run-pass-fulldeps/qquote.rs +++ b/src/test/run-pass-fulldeps/qquote.rs @@ -26,14 +26,6 @@ fn main() { &ps, syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), &mut resolver); - cx.bt_push(syntax::codemap::ExpnInfo { - call_site: DUMMY_SP, - callee: syntax::codemap::NameAndSpan { - format: syntax::codemap::MacroBang(Symbol::intern("")), - allow_internal_unstable: false, - span: None, - } - }); let cx = &mut cx; macro_rules! check { -- cgit 1.4.1-3-g733a5 From f08d5ad4c59ca5fc1c961a94c53807d70959c375 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 15 Mar 2017 00:22:48 +0000 Subject: Refactor how spans are combined in the parser. --- src/librustc/middle/resolve_lifetime.rs | 5 +- src/librustc_metadata/cstore_impl.rs | 4 +- src/librustc_metadata/decoder.rs | 6 +- src/librustc_save_analysis/lib.rs | 2 +- src/librustc_save_analysis/span_utils.rs | 4 +- src/libsyntax/ast.rs | 10 +- src/libsyntax/attr.rs | 15 +- src/libsyntax/codemap.rs | 4 - src/libsyntax/ext/tt/macro_parser.rs | 9 +- src/libsyntax/parse/attr.rs | 29 +- src/libsyntax/parse/lexer/mod.rs | 42 +- src/libsyntax/parse/lexer/unicode_chars.rs | 4 +- src/libsyntax/parse/mod.rs | 6 +- src/libsyntax/parse/parser.rs | 617 ++++++++++----------- src/libsyntax_ext/format.rs | 15 +- src/libsyntax_pos/lib.rs | 16 +- src/test/compile-fail/imports/macro-paths.rs | 2 - src/test/compile-fail/imports/macros.rs | 2 - .../compile-fail/imports/shadow_builtin_macros.rs | 1 - src/test/compile-fail/issue-25385.rs | 1 - src/test/run-pass/syntax-extension-source-utils.rs | 2 +- .../ui/macros/macro_path_as_generic_bound.stderr | 5 +- 22 files changed, 363 insertions(+), 438 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 5094e28475b..8037570d24a 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -29,7 +29,7 @@ use syntax::ast; use syntax::attr; use syntax::ptr::P; use syntax::symbol::keywords; -use syntax_pos::{mk_sp, Span}; +use syntax_pos::Span; use errors::DiagnosticBuilder; use util::nodemap::{NodeMap, NodeSet, FxHashSet, FxHashMap, DefIdMap}; use rustc_back::slice; @@ -1468,8 +1468,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.resolve_lifetime_ref(bound); } else { self.insert_lifetime(bound, Region::Static); - let full_span = mk_sp(lifetime_i.lifetime.span.lo, bound.span.hi); - self.sess.struct_span_warn(full_span, + self.sess.struct_span_warn(lifetime_i.lifetime.span.to(bound.span), &format!("unnecessary lifetime parameter `{}`", lifetime_i.lifetime.name)) .help(&format!("you can use the `'static` lifetime directly, in place \ of `{}`", lifetime_i.lifetime.name)) diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 3e9b6a6226a..41a2e8a8d55 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -36,7 +36,7 @@ use syntax::ast; use syntax::attr; use syntax::parse::filemap_to_stream; use syntax::symbol::Symbol; -use syntax_pos::{mk_sp, Span}; +use syntax_pos::{Span, NO_EXPANSION}; use rustc::hir::svh::Svh; use rustc_back::target::Target; use rustc::hir; @@ -395,7 +395,7 @@ impl CrateStore for cstore::CStore { let source_name = format!("<{} macros>", name); let filemap = sess.parse_sess.codemap().new_filemap(source_name, None, def.body); - let local_span = mk_sp(filemap.start_pos, filemap.end_pos); + let local_span = Span { lo: filemap.start_pos, hi: filemap.end_pos, ctxt: NO_EXPANSION }; let body = filemap_to_stream(&sess.parse_sess, filemap); // Mark the attrs as used diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 3de1e3442c6..43e076e799b 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -39,7 +39,7 @@ use syntax::attr; use syntax::ast; use syntax::codemap; use syntax::ext::base::MacroKind; -use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP}; +use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP, NO_EXPANSION}; pub struct DecodeContext<'a, 'tcx: 'a> { opaque: opaque::Decoder<'a>, @@ -243,7 +243,7 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { let sess = if let Some(sess) = self.sess { sess } else { - return Ok(syntax_pos::mk_sp(lo, hi)); + return Ok(Span { lo: lo, hi: hi, ctxt: NO_EXPANSION }); }; let (lo, hi) = if lo > hi { @@ -290,7 +290,7 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { let lo = (lo - filemap.original_start_pos) + filemap.translated_filemap.start_pos; let hi = (hi - filemap.original_start_pos) + filemap.translated_filemap.start_pos; - Ok(syntax_pos::mk_sp(lo, hi)) + Ok(Span { lo: lo, hi: hi, ctxt: NO_EXPANSION }) } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index fd6803e087a..1de9fbc8e49 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -742,7 +742,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let ident_start = text.find(&name).expect("Name not in signature?"); let ident_end = ident_start + name.len(); Signature { - span: mk_sp(item.span.lo, item.span.lo + BytePos(text.len() as u32)), + span: Span { hi: item.span.lo + BytePos(text.len() as u32), ..item.span }, text: text, ident_start: ident_start, ident_end: ident_end, diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index c19f805a285..af3efb48090 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -305,10 +305,10 @@ impl<'a> SpanUtils<'a> { continue; } if let TokenTree::Token(_, token::Semi) = tok { - return self.snippet(mk_sp(first_span.lo, prev.span().hi)); + return self.snippet(first_span.to(prev.span())); } else if let TokenTree::Delimited(_, ref d) = tok { if d.delim == token::Brace { - return self.snippet(mk_sp(first_span.lo, prev.span().hi)); + return self.snippet(first_span.to(prev.span())); } } prev = tok; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a4bebd311de..9eb86aa006d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -17,7 +17,7 @@ pub use self::PathParameters::*; pub use symbol::{Ident, Symbol as Name}; pub use util::ThinVec; -use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP}; +use syntax_pos::{Span, DUMMY_SP}; use codemap::{respan, Spanned}; use abi::Abi; use ext::hygiene::{Mark, SyntaxContext}; @@ -1433,7 +1433,7 @@ impl Arg { TyKind::Rptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyKind::ImplicitSelf => { Some(respan(self.pat.span, SelfKind::Region(lt, mutbl))) } - _ => Some(respan(mk_sp(self.pat.span.lo, self.ty.span.hi), + _ => Some(respan(self.pat.span.to(self.ty.span), SelfKind::Explicit(self.ty.clone(), mutbl))), } } @@ -1450,7 +1450,7 @@ impl Arg { } pub fn from_self(eself: ExplicitSelf, eself_ident: SpannedIdent) -> Arg { - let span = mk_sp(eself.span.lo, eself_ident.span.hi); + let span = eself.span.to(eself_ident.span); let infer_ty = P(Ty { id: DUMMY_NODE_ID, node: TyKind::ImplicitSelf, @@ -1687,11 +1687,11 @@ pub struct PolyTraitRef { } impl PolyTraitRef { - pub fn new(lifetimes: Vec, path: Path, lo: BytePos, hi: BytePos) -> Self { + pub fn new(lifetimes: Vec, path: Path, span: Span) -> Self { PolyTraitRef { bound_lifetimes: lifetimes, trait_ref: TraitRef { path: path, ref_id: DUMMY_NODE_ID }, - span: mk_sp(lo, hi), + span: span, } } } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 2f1efd6ad00..5dcce2572af 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -18,8 +18,8 @@ use ast; use ast::{AttrId, Attribute, Name, Ident}; use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind}; -use codemap::{Spanned, spanned, dummy_spanned, mk_sp}; -use syntax_pos::{Span, BytePos, DUMMY_SP}; +use codemap::{Spanned, respan, dummy_spanned}; +use syntax_pos::{Span, DUMMY_SP}; use errors::Handler; use feature_gate::{Features, GatedCfg}; use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; @@ -447,17 +447,16 @@ pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute } } -pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, lo: BytePos, hi: BytePos) - -> Attribute { +pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, span: Span) -> Attribute { let style = doc_comment_style(&text.as_str()); - let lit = spanned(lo, hi, LitKind::Str(text, ast::StrStyle::Cooked)); + let lit = respan(span, LitKind::Str(text, ast::StrStyle::Cooked)); Attribute { id: id, style: style, - path: ast::Path::from_ident(mk_sp(lo, hi), ast::Ident::from_str("doc")), - tokens: MetaItemKind::NameValue(lit).tokens(mk_sp(lo, hi)), + path: ast::Path::from_ident(span, ast::Ident::from_str("doc")), + tokens: MetaItemKind::NameValue(lit).tokens(span), is_sugared_doc: true, - span: mk_sp(lo, hi), + span: span, } } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index ba199eacb62..4d67390d442 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -49,10 +49,6 @@ pub struct Spanned { pub span: Span, } -pub fn spanned(lo: BytePos, hi: BytePos, t: T) -> Spanned { - respan(mk_sp(lo, hi), t) -} - pub fn respan(sp: Span, t: T) -> Spanned { Spanned {node: t, span: sp} } diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index ed17f0f956c..9ee427eed35 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -79,7 +79,7 @@ pub use self::ParseResult::*; use self::TokenTreeOrTokenTreeVec::*; use ast::Ident; -use syntax_pos::{self, BytePos, mk_sp, Span}; +use syntax_pos::{self, BytePos, Span}; use codemap::Spanned; use errors::FatalError; use ext::tt::quoted::{self, TokenTree}; @@ -285,7 +285,7 @@ fn inner_parse_loop(sess: &ParseSess, eof_eis: &mut SmallVector>, bb_eis: &mut SmallVector>, token: &Token, - span: &syntax_pos::Span) + span: syntax_pos::Span) -> ParseResult<()> { while let Some(mut ei) = cur_eis.pop() { // When unzipped trees end, remove them @@ -323,8 +323,7 @@ fn inner_parse_loop(sess: &ParseSess, for idx in ei.match_lo..ei.match_hi { let sub = ei.matches[idx].clone(); new_pos.matches[idx] - .push(Rc::new(MatchedSeq(sub, mk_sp(ei.sp_lo, - span.hi)))); + .push(Rc::new(MatchedSeq(sub, Span { lo: ei.sp_lo, ..span }))); } new_pos.match_cur = ei.match_hi; @@ -426,7 +425,7 @@ pub fn parse(sess: &ParseSess, tts: TokenStream, ms: &[TokenTree], directory: Op assert!(next_eis.is_empty()); match inner_parse_loop(sess, &mut cur_eis, &mut next_eis, &mut eof_eis, &mut bb_eis, - &parser.token, &parser.span) { + &parser.token, parser.span) { Success(_) => {}, Failure(sp, tok) => return Failure(sp, tok), Error(sp, msg) => return Error(sp, msg), diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 53106214fa3..92cec462ffb 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -10,8 +10,7 @@ use attr; use ast; -use syntax_pos::{mk_sp, Span}; -use codemap::spanned; +use codemap::respan; use parse::common::SeqSep; use parse::PResult; use parse::token::{self, Nonterminal}; @@ -49,8 +48,7 @@ impl<'a> Parser<'a> { just_parsed_doc_comment = false; } token::DocComment(s) => { - let Span { lo, hi, .. } = self.span; - let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, lo, hi); + let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.span); if attr.style != ast::AttrStyle::Outer { let mut err = self.fatal("expected outer doc comment"); err.note("inner doc comments like this (starting with \ @@ -94,7 +92,7 @@ impl<'a> Parser<'a> { self.token); let (span, path, tokens, mut style) = match self.token { token::Pound => { - let lo = self.span.lo; + let lo = self.span; self.bump(); if inner_parse_policy == InnerAttributeParsePolicy::Permitted { @@ -122,9 +120,9 @@ impl<'a> Parser<'a> { self.expect(&token::OpenDelim(token::Bracket))?; let (path, tokens) = self.parse_path_and_tokens()?; self.expect(&token::CloseDelim(token::Bracket))?; - let hi = self.prev_span.hi; + let hi = self.prev_span; - (mk_sp(lo, hi), path, tokens, style) + (lo.to(hi), path, tokens, style) } _ => { let token_str = self.this_token_to_string(); @@ -189,8 +187,7 @@ impl<'a> Parser<'a> { } token::DocComment(s) => { // we need to get the position of this token before we bump. - let Span { lo, hi, .. } = self.span; - let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, lo, hi); + let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.span); if attr.style == ast::AttrStyle::Inner { attrs.push(attr); self.bump(); @@ -238,11 +235,10 @@ impl<'a> Parser<'a> { return Ok(meta); } - let lo = self.span.lo; + let lo = self.span; let ident = self.parse_ident()?; let node = self.parse_meta_item_kind()?; - let hi = self.prev_span.hi; - Ok(ast::MetaItem { name: ident.name, node: node, span: mk_sp(lo, hi) }) + Ok(ast::MetaItem { name: ident.name, node: node, span: lo.to(self.prev_span) }) } pub fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> { @@ -258,26 +254,25 @@ impl<'a> Parser<'a> { /// 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; + let lo = self.span; match self.parse_unsuffixed_lit() { Ok(lit) => { - return Ok(spanned(lo, self.prev_span.hi, ast::NestedMetaItemKind::Literal(lit))) + return Ok(respan(lo.to(self.prev_span), ast::NestedMetaItemKind::Literal(lit))) } Err(ref mut err) => self.diagnostic().cancel(err) } match self.parse_meta_item() { Ok(mi) => { - return Ok(spanned(lo, self.prev_span.hi, ast::NestedMetaItemKind::MetaItem(mi))) + return Ok(respan(lo.to(self.prev_span), 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)) + Err(self.diagnostic().struct_span_err(lo, &msg)) } /// matches meta_seq = ( COMMASEP(meta_item_inner) ) diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index d48cf6911ed..920b2c401e2 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -9,7 +9,7 @@ // except according to those terms. use ast::{self, Ident}; -use syntax_pos::{self, BytePos, CharPos, Pos, Span}; +use syntax_pos::{self, BytePos, CharPos, Pos, Span, NO_EXPANSION}; use codemap::CodeMap; use errors::{FatalError, DiagnosticBuilder}; use parse::{token, ParseSess}; @@ -68,6 +68,10 @@ pub struct StringReader<'a> { open_braces: Vec<(token::DelimToken, Span)>, } +fn mk_sp(lo: BytePos, hi: BytePos) -> Span { + Span { lo: lo, hi: hi, ctxt: NO_EXPANSION } +} + impl<'a> StringReader<'a> { fn next_token(&mut self) -> TokenAndSpan where Self: Sized { let res = self.try_next_token(); @@ -225,12 +229,12 @@ impl<'a> StringReader<'a> { /// Report a fatal error spanning [`from_pos`, `to_pos`). fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> FatalError { - self.fatal_span(syntax_pos::mk_sp(from_pos, to_pos), m) + self.fatal_span(mk_sp(from_pos, to_pos), m) } /// Report a lexical error spanning [`from_pos`, `to_pos`). fn err_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) { - self.err_span(syntax_pos::mk_sp(from_pos, to_pos), m) + self.err_span(mk_sp(from_pos, to_pos), m) } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an @@ -254,7 +258,7 @@ impl<'a> StringReader<'a> { for c in c.escape_default() { m.push(c) } - self.sess.span_diagnostic.struct_span_fatal(syntax_pos::mk_sp(from_pos, to_pos), &m[..]) + self.sess.span_diagnostic.struct_span_fatal(mk_sp(from_pos, to_pos), &m[..]) } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an @@ -278,7 +282,7 @@ impl<'a> StringReader<'a> { for c in c.escape_default() { m.push(c) } - self.sess.span_diagnostic.struct_span_err(syntax_pos::mk_sp(from_pos, to_pos), &m[..]) + self.sess.span_diagnostic.struct_span_err(mk_sp(from_pos, to_pos), &m[..]) } /// Report a lexical error spanning [`from_pos`, `to_pos`), appending the @@ -302,11 +306,11 @@ impl<'a> StringReader<'a> { None => { if self.is_eof() { self.peek_tok = token::Eof; - self.peek_span = syntax_pos::mk_sp(self.filemap.end_pos, self.filemap.end_pos); + self.peek_span = mk_sp(self.filemap.end_pos, self.filemap.end_pos); } else { let start_bytepos = self.pos; self.peek_tok = self.next_token_inner()?; - self.peek_span = syntax_pos::mk_sp(start_bytepos, self.pos); + self.peek_span = mk_sp(start_bytepos, self.pos); }; } } @@ -489,7 +493,7 @@ impl<'a> StringReader<'a> { if let Some(c) = self.ch { if c.is_whitespace() { let msg = "called consume_any_line_comment, but there was whitespace"; - self.sess.span_diagnostic.span_err(syntax_pos::mk_sp(self.pos, self.pos), msg); + self.sess.span_diagnostic.span_err(mk_sp(self.pos, self.pos), msg); } } @@ -532,13 +536,13 @@ impl<'a> StringReader<'a> { Some(TokenAndSpan { tok: tok, - sp: syntax_pos::mk_sp(start_bpos, self.pos), + sp: mk_sp(start_bpos, self.pos), }) }) } else { Some(TokenAndSpan { tok: token::Comment, - sp: syntax_pos::mk_sp(start_bpos, self.pos), + sp: mk_sp(start_bpos, self.pos), }) }; } @@ -571,7 +575,7 @@ impl<'a> StringReader<'a> { } return Some(TokenAndSpan { tok: token::Shebang(self.name_from(start)), - sp: syntax_pos::mk_sp(start, self.pos), + sp: mk_sp(start, self.pos), }); } } @@ -599,7 +603,7 @@ impl<'a> StringReader<'a> { } let c = Some(TokenAndSpan { tok: token::Whitespace, - sp: syntax_pos::mk_sp(start_bpos, self.pos), + sp: mk_sp(start_bpos, self.pos), }); debug!("scanning whitespace: {:?}", c); c @@ -661,7 +665,7 @@ impl<'a> StringReader<'a> { Some(TokenAndSpan { tok: tok, - sp: syntax_pos::mk_sp(start_bpos, self.pos), + sp: mk_sp(start_bpos, self.pos), }) }) } @@ -858,7 +862,7 @@ impl<'a> StringReader<'a> { let valid = if self.ch_is('{') { self.scan_unicode_escape(delim) && !ascii_only } else { - let span = syntax_pos::mk_sp(start, self.pos); + let span = mk_sp(start, self.pos); self.sess.span_diagnostic .struct_span_err(span, "incorrect unicode escape sequence") .span_help(span, @@ -896,13 +900,13 @@ impl<'a> StringReader<'a> { }, c); if e == '\r' { - err.span_help(syntax_pos::mk_sp(escaped_pos, pos), + err.span_help(mk_sp(escaped_pos, pos), "this is an isolated carriage return; consider \ checking your editor and version control \ settings"); } if (e == '{' || e == '}') && !ascii_only { - err.span_help(syntax_pos::mk_sp(escaped_pos, pos), + err.span_help(mk_sp(escaped_pos, pos), "if used in a formatting string, curly braces \ are escaped with `{{` and `}}`"); } @@ -1735,7 +1739,7 @@ mod tests { sp: Span { lo: BytePos(21), hi: BytePos(23), - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, }, }; assert_eq!(tok1, tok2); @@ -1749,7 +1753,7 @@ mod tests { sp: Span { lo: BytePos(24), hi: BytePos(28), - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, }, }; assert_eq!(tok3, tok4); @@ -1908,7 +1912,7 @@ mod tests { let mut lexer = setup(&cm, &sh, "// test\r\n/// test\r\n".to_string()); let comment = lexer.next_token(); assert_eq!(comment.tok, token::Comment); - assert_eq!(comment.sp, ::syntax_pos::mk_sp(BytePos(0), BytePos(7))); + assert_eq!((comment.sp.lo, comment.sp.hi), (BytePos(0), BytePos(7))); assert_eq!(lexer.next_token().tok, token::Whitespace); assert_eq!(lexer.next_token().tok, token::DocComment(Symbol::intern("/// test"))); diff --git a/src/libsyntax/parse/lexer/unicode_chars.rs b/src/libsyntax/parse/lexer/unicode_chars.rs index 6da3e5de75c..4df23da3c9c 100644 --- a/src/libsyntax/parse/lexer/unicode_chars.rs +++ b/src/libsyntax/parse/lexer/unicode_chars.rs @@ -11,7 +11,7 @@ // Characters and their corresponding confusables were collected from // http://www.unicode.org/Public/security/revision-06/confusables.txt -use syntax_pos::mk_sp as make_span; +use syntax_pos::{Span, NO_EXPANSION}; use errors::DiagnosticBuilder; use super::StringReader; @@ -234,7 +234,7 @@ pub fn check_for_substitution<'a>(reader: &StringReader<'a>, .iter() .find(|&&(c, _, _)| c == ch) .map(|&(_, u_name, ascii_char)| { - let span = make_span(reader.pos, reader.next_pos); + let span = Span { lo: reader.pos, hi: reader.next_pos, ctxt: NO_EXPANSION }; match ASCII_ARRAY.iter().find(|&&(c, _)| c == ascii_char) { Some(&(ascii_char, ascii_name)) => { let msg = diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index e188bcaf105..b5d0a46de49 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -12,7 +12,7 @@ use ast::{self, CrateConfig}; use codemap::CodeMap; -use syntax_pos::{self, Span, FileMap}; +use syntax_pos::{self, Span, FileMap, NO_EXPANSION}; use errors::{Handler, ColorConfig, DiagnosticBuilder}; use feature_gate::UnstableFeatures; use parse::parser::Parser; @@ -178,7 +178,7 @@ pub fn filemap_to_parser<'a>(sess: &'a ParseSess, filemap: Rc, ) -> Par let mut parser = stream_to_parser(sess, filemap_to_stream(sess, filemap)); if parser.token == token::Eof && parser.span == syntax_pos::DUMMY_SP { - parser.span = syntax_pos::mk_sp(end_pos, end_pos); + parser.span = Span { lo: end_pos, hi: end_pos, ctxt: NO_EXPANSION }; } parser @@ -665,7 +665,7 @@ mod tests { // produce a syntax_pos::span fn sp(a: u32, b: u32) -> Span { - Span {lo: BytePos(a), hi: BytePos(b), expn_id: NO_EXPANSION} + Span {lo: BytePos(a), hi: BytePos(b), ctxt: NO_EXPANSION} } fn str2seg(s: &str, lo: u32, hi: u32) -> ast::PathSegment { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e9eb4fbcc91..b0611d75290 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -40,8 +40,8 @@ use ast::{Visibility, WhereClause}; use ast::{BinOpKind, UnOp}; use ast::RangeEnd; use {ast, attr}; -use codemap::{self, CodeMap, Spanned, spanned, respan}; -use syntax_pos::{self, Span, BytePos, mk_sp}; +use codemap::{self, CodeMap, Spanned, respan}; +use syntax_pos::{self, Span, BytePos}; use errors::{self, DiagnosticBuilder}; use parse::{self, classify, token}; use parse::common::SeqSep; @@ -108,13 +108,13 @@ macro_rules! maybe_whole_expr { $p.bump(); let span = $p.span; let kind = ExprKind::Path(None, (*path).clone()); - return Ok($p.mk_expr(span.lo, span.hi, kind, ThinVec::new())); + return Ok($p.mk_expr(span, kind, ThinVec::new())); } token::NtBlock(ref block) => { $p.bump(); let span = $p.span; let kind = ExprKind::Block((*block).clone()); - return Ok($p.mk_expr(span.lo, span.hi, kind, ThinVec::new())); + return Ok($p.mk_expr(span, kind, ThinVec::new())); } _ => {}, }; @@ -731,7 +731,7 @@ impl<'a> Parser<'a> { token::AndAnd => { let span = self.span; let lo = span.lo + BytePos(1); - Ok(self.bump_with(token::BinOp(token::And), lo, span.hi)) + Ok(self.bump_with(token::BinOp(token::And), Span { lo: lo, ..span })) } _ => self.unexpected() } @@ -765,7 +765,7 @@ impl<'a> Parser<'a> { token::BinOp(token::Shl) => { let span = self.span; let lo = span.lo + BytePos(1); - self.bump_with(token::Lt, lo, span.hi); + self.bump_with(token::Lt, Span { lo: lo, ..span }); true } _ => false, @@ -793,17 +793,17 @@ impl<'a> Parser<'a> { token::BinOp(token::Shr) => { let span = self.span; let lo = span.lo + BytePos(1); - Ok(self.bump_with(token::Gt, lo, span.hi)) + Ok(self.bump_with(token::Gt, Span { lo: lo, ..span })) } token::BinOpEq(token::Shr) => { let span = self.span; let lo = span.lo + BytePos(1); - Ok(self.bump_with(token::Ge, lo, span.hi)) + Ok(self.bump_with(token::Ge, Span { lo: lo, ..span })) } token::Ge => { let span = self.span; let lo = span.lo + BytePos(1); - Ok(self.bump_with(token::Eq, lo, span.hi)) + Ok(self.bump_with(token::Eq, Span { lo: lo, ..span })) } _ => self.unexpected() } @@ -997,12 +997,12 @@ impl<'a> Parser<'a> { -> PResult<'a, Spanned>> where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, { - let lo = self.span.lo; + let lo = self.span; self.expect(bra)?; let result = self.parse_seq_to_before_end(ket, sep, f); - let hi = self.span.hi; + let hi = self.span; self.bump(); - Ok(spanned(lo, hi, result)) + Ok(respan(lo.to(hi), result)) } /// Advance the parser by one token @@ -1033,16 +1033,13 @@ impl<'a> Parser<'a> { /// Advance the parser using provided token as a next one. Use this when /// consuming a part of a token. For example a single `<` from `<<`. - pub fn bump_with(&mut self, - next: token::Token, - lo: BytePos, - hi: BytePos) { - self.prev_span = mk_sp(self.span.lo, lo); + pub fn bump_with(&mut self, next: token::Token, span: Span) { + self.prev_span = Span { hi: span.lo, ..self.span }; // It would be incorrect to record the kind of the current token, but // fortunately for tokens currently using `bump_with`, the // prev_token_kind will be of no use anyway. self.prev_token_kind = PrevTokenKind::Other; - self.span = mk_sp(lo, hi); + self.span = span; self.token = next; self.expected_tokens.clear(); } @@ -1173,7 +1170,7 @@ impl<'a> Parser<'a> { pub fn parse_trait_item(&mut self) -> PResult<'a, TraitItem> { maybe_whole!(self, NtTraitItem, |x| x); let mut attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; let (name, node) = if self.eat_keyword(keywords::Type) { let TyParam {ident, bounds, default, ..} = self.parse_ty_param(vec![])?; @@ -1197,7 +1194,7 @@ impl<'a> Parser<'a> { } else if self.token.is_path_start() { // trait item macro. // code copied from parse_macro_use_or_failure... abstraction! - let lo = self.span.lo; + let lo = self.span; let pth = self.parse_path(PathStyle::Mod)?; self.expect(&token::Not)?; @@ -1207,7 +1204,7 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)? } - let mac = spanned(lo, self.prev_span.hi, Mac_ { path: pth, tts: tts }); + let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts }); (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac)) } else { let (constness, unsafety, abi) = match self.parse_fn_front_matter() { @@ -1277,7 +1274,7 @@ impl<'a> Parser<'a> { ident: name, attrs: attrs, node: node, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), }) } @@ -1298,8 +1295,7 @@ impl<'a> Parser<'a> { if self.eat(&token::RArrow) { Ok(FunctionRetTy::Ty(self.parse_ty_no_plus()?)) } else { - let pos = self.span.lo; - Ok(FunctionRetTy::Default(mk_sp(pos, pos))) + Ok(FunctionRetTy::Default(Span { hi: self.span.lo, ..self.span })) } } @@ -1320,7 +1316,7 @@ impl<'a> Parser<'a> { fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P> { maybe_whole!(self, NtTy, |x| x); - let lo = self.span.lo; + let lo = self.span; let node = if self.eat(&token::OpenDelim(token::Paren)) { // `(TYPE)` is a parenthesized type. // `(TYPE,)` is a tuple with a single field of type TYPE. @@ -1344,7 +1340,7 @@ impl<'a> Parser<'a> { TyKind::Path(None, ref path) if allow_plus && self.token == token::BinOp(token::Plus) => { self.bump(); // `+` - let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo, self.prev_span.hi); + let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo.to(self.prev_span)); let mut bounds = vec![TraitTyParamBound(pt, TraitBoundModifier::None)]; bounds.append(&mut self.parse_ty_param_bounds()?); TyKind::TraitObject(bounds) @@ -1394,13 +1390,13 @@ impl<'a> Parser<'a> { if self.eat(&token::Not) { // Macro invocation in type position let (_, tts) = self.expect_delimited_token_tree()?; - TyKind::Mac(spanned(lo, self.span.hi, Mac_ { path: path, tts: tts })) + TyKind::Mac(respan(lo.to(self.span), Mac_ { path: path, tts: tts })) } else { // Just a type path or bound list (trait object type) starting with a trait. // `Type` // `Trait1 + Trait2 + 'a` if allow_plus && self.eat(&token::BinOp(token::Plus)) { - let poly_trait = PolyTraitRef::new(Vec::new(), path, lo, self.prev_span.hi); + let poly_trait = PolyTraitRef::new(Vec::new(), path, lo.to(self.prev_span)); let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)]; bounds.append(&mut self.parse_ty_param_bounds()?); TyKind::TraitObject(bounds) @@ -1415,13 +1411,13 @@ impl<'a> Parser<'a> { // Function pointer type or bound list (trait object type) starting with a poly-trait. // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` // `for<'lt> Trait1<'lt> + Trait2 + 'a` - let lo = self.span.lo; + let lo = self.span; let lifetime_defs = self.parse_late_bound_lifetime_defs()?; if self.token_is_bare_fn_keyword() { self.parse_ty_bare_fn(lifetime_defs)? } else { let path = self.parse_path(PathStyle::Type)?; - let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo, self.prev_span.hi); + let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)]; if allow_plus && self.eat(&token::BinOp(token::Plus)) { bounds.append(&mut self.parse_ty_param_bounds()?) @@ -1440,7 +1436,7 @@ impl<'a> Parser<'a> { return Err(self.fatal(&msg)); }; - let span = mk_sp(lo, self.prev_span.hi); + let span = lo.to(self.prev_span); let ty = Ty { node: node, span: span, id: ast::DUMMY_NODE_ID }; // Try to recover from use of `+` with incorrect priority. @@ -1457,7 +1453,7 @@ impl<'a> Parser<'a> { self.bump(); // `+` let bounds = self.parse_ty_param_bounds()?; - let sum_span = mk_sp(ty.span.lo, self.prev_span.hi); + let sum_span = ty.span.to(self.prev_span); let mut err = struct_span_err!(self.sess.span_diagnostic, ty.span, E0178, "expected a path on the left-hand side of `+`, not `{}`", pprust::ty_to_string(&ty)); @@ -1577,7 +1573,7 @@ impl<'a> Parser<'a> { P(Ty { id: ast::DUMMY_NODE_ID, node: TyKind::Infer, - span: mk_sp(self.span.lo, self.span.hi), + span: self.span, }) }; Ok(Arg { @@ -1625,7 +1621,7 @@ impl<'a> Parser<'a> { /// Matches lit = true | false | token_lit pub fn parse_lit(&mut self) -> PResult<'a, Lit> { - let lo = self.span.lo; + let lo = self.span; let lit = if self.eat_keyword(keywords::True) { LitKind::Bool(true) } else if self.eat_keyword(keywords::False) { @@ -1634,22 +1630,22 @@ impl<'a> Parser<'a> { let lit = self.parse_lit_token()?; lit }; - Ok(codemap::Spanned { node: lit, span: mk_sp(lo, self.prev_span.hi) }) + Ok(codemap::Spanned { node: lit, span: lo.to(self.prev_span) }) } /// matches '-' lit | lit pub fn parse_pat_literal_maybe_minus(&mut self) -> PResult<'a, P> { - let minus_lo = self.span.lo; + let minus_lo = self.span; let minus_present = self.eat(&token::BinOp(token::Minus)); - let lo = self.span.lo; + let lo = self.span; let literal = P(self.parse_lit()?); - let hi = self.prev_span.hi; - let expr = self.mk_expr(lo, hi, ExprKind::Lit(literal), ThinVec::new()); + let hi = self.prev_span; + let expr = self.mk_expr(lo.to(hi), ExprKind::Lit(literal), ThinVec::new()); if minus_present { - let minus_hi = self.prev_span.hi; + let minus_hi = self.prev_span; let unary = self.mk_unary(UnOp::Neg, expr); - Ok(self.mk_expr(minus_lo, minus_hi, unary, ThinVec::new())) + Ok(self.mk_expr(minus_lo.to(minus_hi), unary, ThinVec::new())) } else { Ok(expr) } @@ -1726,7 +1722,7 @@ impl<'a> Parser<'a> { pub fn parse_path(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> { maybe_whole!(self, NtPath, |x| x); - let lo = self.span.lo; + let lo = self.span; let is_global = self.eat(&token::ModSep); // Parse any number of segments and bound sets. A segment is an @@ -1750,7 +1746,7 @@ impl<'a> Parser<'a> { // Assemble the span. // FIXME(#39450) This is bogus if part of the path is macro generated. - let span = mk_sp(lo, self.prev_span.hi); + let span = lo.to(self.prev_span); // Assemble the result. Ok(ast::Path { @@ -1791,7 +1787,7 @@ impl<'a> Parser<'a> { bindings: bindings, }.into() } else if self.eat(&token::OpenDelim(token::Paren)) { - let lo = self.prev_span.lo; + let lo = self.prev_span; let inputs = self.parse_seq_to_end( &token::CloseDelim(token::Paren), @@ -1804,10 +1800,10 @@ impl<'a> Parser<'a> { None }; - let hi = self.prev_span.hi; + let hi = self.prev_span; Some(P(ast::PathParameters::Parenthesized(ast::ParenthesizedParameterData { - span: mk_sp(lo, hi), + span: lo.to(hi), inputs: inputs, output: output_ty, }))) @@ -1928,38 +1924,37 @@ impl<'a> Parser<'a> { /// Parse ident (COLON expr)? pub fn parse_field(&mut self) -> PResult<'a, Field> { let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; let hi; // Check if a colon exists one ahead. This means we're parsing a fieldname. let (fieldname, expr, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) { let fieldname = self.parse_field_name()?; self.bump(); - hi = self.prev_span.hi; + hi = self.prev_span; (fieldname, self.parse_expr()?, false) } else { let fieldname = self.parse_ident()?; - hi = self.prev_span.hi; + hi = self.prev_span; // Mimic `x: x` for the `x` field shorthand. - let path = ast::Path::from_ident(mk_sp(lo, hi), fieldname); - (fieldname, self.mk_expr(lo, hi, ExprKind::Path(None, path), ThinVec::new()), true) + let path = ast::Path::from_ident(lo.to(hi), fieldname); + (fieldname, self.mk_expr(lo.to(hi), ExprKind::Path(None, path), ThinVec::new()), true) }; Ok(ast::Field { - ident: spanned(lo, hi, fieldname), - span: mk_sp(lo, expr.span.hi), + ident: respan(lo.to(hi), fieldname), + span: lo.to(expr.span), expr: expr, is_shorthand: is_shorthand, attrs: attrs.into(), }) } - pub fn mk_expr(&mut self, lo: BytePos, hi: BytePos, node: ExprKind, attrs: ThinVec) - -> P { + pub fn mk_expr(&mut self, span: Span, node: ExprKind, attrs: ThinVec) -> P { P(Expr { id: ast::DUMMY_NODE_ID, node: node, - span: mk_sp(lo, hi), + span: span, attrs: attrs.into(), }) } @@ -2013,12 +2008,11 @@ impl<'a> Parser<'a> { ExprKind::AssignOp(binop, lhs, rhs) } - pub fn mk_mac_expr(&mut self, lo: BytePos, hi: BytePos, - m: Mac_, attrs: ThinVec) -> P { + pub fn mk_mac_expr(&mut self, span: Span, m: Mac_, attrs: ThinVec) -> P { P(Expr { id: ast::DUMMY_NODE_ID, - node: ExprKind::Mac(codemap::Spanned {node: m, span: mk_sp(lo, hi)}), - span: mk_sp(lo, hi), + node: ExprKind::Mac(codemap::Spanned {node: m, span: span}), + span: span, attrs: attrs, }) } @@ -2065,8 +2059,8 @@ impl<'a> Parser<'a> { // attributes by giving them a empty "already parsed" list. let mut attrs = ThinVec::new(); - let lo = self.span.lo; - let mut hi = self.span.hi; + let lo = self.span; + let mut hi = self.span; let ex: ExprKind; @@ -2095,18 +2089,19 @@ impl<'a> Parser<'a> { } self.bump(); - hi = self.prev_span.hi; + hi = self.prev_span; + let span = lo.to(hi); return if es.len() == 1 && !trailing_comma { - Ok(self.mk_expr(lo, hi, ExprKind::Paren(es.into_iter().nth(0).unwrap()), attrs)) + Ok(self.mk_expr(span, ExprKind::Paren(es.into_iter().nth(0).unwrap()), attrs)) } else { - Ok(self.mk_expr(lo, hi, ExprKind::Tup(es), attrs)) + Ok(self.mk_expr(span, ExprKind::Tup(es), attrs)) } }, token::OpenDelim(token::Brace) => { return self.parse_block_expr(lo, BlockCheckMode::Default, attrs); }, token::BinOp(token::Or) | token::OrOr => { - let lo = self.span.lo; + let lo = self.span; return self.parse_lambda_expr(lo, CaptureBy::Ref, attrs); }, token::OpenDelim(token::Bracket) => { @@ -2144,34 +2139,34 @@ impl<'a> Parser<'a> { ex = ExprKind::Array(vec![first_expr]); } } - hi = self.prev_span.hi; + hi = self.prev_span; } _ => { if self.eat_lt() { let (qself, path) = self.parse_qualified_path(PathStyle::Expr)?; - hi = path.span.hi; - return Ok(self.mk_expr(lo, hi, ExprKind::Path(Some(qself), path), attrs)); + hi = path.span; + return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs)); } if self.eat_keyword(keywords::Move) { - let lo = self.prev_span.lo; + let lo = self.prev_span; return self.parse_lambda_expr(lo, CaptureBy::Value, attrs); } if self.eat_keyword(keywords::If) { return self.parse_if_expr(attrs); } if self.eat_keyword(keywords::For) { - let lo = self.prev_span.lo; + let lo = self.prev_span; return self.parse_for_expr(None, lo, attrs); } if self.eat_keyword(keywords::While) { - let lo = self.prev_span.lo; + let lo = self.prev_span; return self.parse_while_expr(None, lo, attrs); } if self.token.is_lifetime() { let label = Spanned { node: self.get_label(), span: self.span }; - let lo = self.span.lo; + let lo = self.span; self.bump(); self.expect(&token::Colon)?; if self.eat_keyword(keywords::While) { @@ -2186,7 +2181,7 @@ impl<'a> Parser<'a> { return Err(self.fatal("expected `while`, `for`, or `loop` after a label")) } if self.eat_keyword(keywords::Loop) { - let lo = self.prev_span.lo; + let lo = self.prev_span; return self.parse_loop_expr(None, lo, attrs); } if self.eat_keyword(keywords::Continue) { @@ -2200,8 +2195,8 @@ impl<'a> Parser<'a> { } else { ExprKind::Continue(None) }; - let hi = self.prev_span.hi; - return Ok(self.mk_expr(lo, hi, ex, attrs)); + let hi = self.prev_span; + return Ok(self.mk_expr(lo.to(hi), ex, attrs)); } if self.eat_keyword(keywords::Match) { return self.parse_match_expr(attrs); @@ -2215,13 +2210,13 @@ impl<'a> Parser<'a> { if self.is_catch_expr() { assert!(self.eat_keyword(keywords::Do)); assert!(self.eat_keyword(keywords::Catch)); - let lo = self.prev_span.lo; + let lo = self.prev_span; return self.parse_catch_expr(lo, attrs); } if self.eat_keyword(keywords::Return) { if self.token.can_begin_expr() { let e = self.parse_expr()?; - hi = e.span.hi; + hi = e.span; ex = ExprKind::Ret(Some(e)); } else { ex = ExprKind::Ret(None); @@ -2246,7 +2241,7 @@ impl<'a> Parser<'a> { None }; ex = ExprKind::Break(lt, e); - hi = self.prev_span.hi; + hi = self.prev_span; } else if self.token.is_keyword(keywords::Let) { // Catch this syntax error here, instead of in `check_strict_keywords`, so // that we can explicitly mention that let is not to be used as an expression @@ -2260,8 +2255,8 @@ impl<'a> Parser<'a> { if self.eat(&token::Not) { // MACRO INVOCATION expression let (_, tts) = self.expect_delimited_token_tree()?; - let hi = self.prev_span.hi; - return Ok(self.mk_mac_expr(lo, hi, Mac_ { path: pth, tts: tts }, attrs)); + let hi = self.prev_span; + return Ok(self.mk_mac_expr(lo.to(hi), Mac_ { path: pth, tts: tts }, attrs)); } if self.check(&token::OpenDelim(token::Brace)) { // This is a struct literal, unless we're prohibited @@ -2274,12 +2269,12 @@ impl<'a> Parser<'a> { } } - hi = pth.span.hi; + hi = pth.span; ex = ExprKind::Path(None, pth); } else { match self.parse_lit() { Ok(lit) => { - hi = lit.span.hi; + hi = lit.span; ex = ExprKind::Lit(P(lit)); } Err(mut err) => { @@ -2293,10 +2288,10 @@ impl<'a> Parser<'a> { } } - return Ok(self.mk_expr(lo, hi, ex, attrs)); + return Ok(self.mk_expr(lo.to(hi), ex, attrs)); } - fn parse_struct_expr(&mut self, lo: BytePos, pth: ast::Path, mut attrs: ThinVec) + fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec) -> PResult<'a, P> { self.bump(); let mut fields = Vec::new(); @@ -2338,9 +2333,9 @@ impl<'a> Parser<'a> { } } - let hi = self.span.hi; + let span = lo.to(self.span); self.expect(&token::CloseDelim(token::Brace))?; - return Ok(self.mk_expr(lo, hi, ExprKind::Struct(pth, fields, base), attrs)); + return Ok(self.mk_expr(span, ExprKind::Struct(pth, fields, base), attrs)); } fn parse_or_use_outer_attributes(&mut self, @@ -2354,7 +2349,7 @@ impl<'a> Parser<'a> { } /// Parse a block or unsafe block - pub fn parse_block_expr(&mut self, lo: BytePos, blk_mode: BlockCheckMode, + pub fn parse_block_expr(&mut self, lo: Span, blk_mode: BlockCheckMode, outer_attrs: ThinVec) -> PResult<'a, P> { @@ -2364,7 +2359,7 @@ impl<'a> Parser<'a> { attrs.extend(self.parse_inner_attributes()?); let blk = self.parse_block_tail(lo, blk_mode)?; - return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprKind::Block(blk), attrs)); + return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), attrs)); } /// parse a.b or a(13) or a[4] or just a @@ -2375,12 +2370,12 @@ impl<'a> Parser<'a> { let b = self.parse_bottom_expr(); let (span, b) = self.interpolated_or_expr_span(b)?; - self.parse_dot_or_call_expr_with(b, span.lo, attrs) + self.parse_dot_or_call_expr_with(b, span, attrs) } pub fn parse_dot_or_call_expr_with(&mut self, e0: P, - lo: BytePos, + lo: Span, mut attrs: ThinVec) -> PResult<'a, P> { // Stitch the list of outer attributes onto the return value. @@ -2411,11 +2406,7 @@ impl<'a> Parser<'a> { // Assuming we have just parsed `.foo` (i.e., a dot and an ident), continue // parsing into an expression. - fn parse_dot_suffix(&mut self, - ident: Ident, - ident_span: Span, - self_value: P, - lo: BytePos) + fn parse_dot_suffix(&mut self, ident: Ident, ident_span: Span, self_value: P, lo: Span) -> PResult<'a, P> { let (_, tys, bindings) = if self.eat(&token::ModSep) { self.expect_lt()?; @@ -2440,12 +2431,12 @@ impl<'a> Parser<'a> { SeqSep::trailing_allowed(token::Comma), |p| Ok(p.parse_expr()?) )?; - let hi = self.prev_span.hi; + let hi = self.prev_span; es.insert(0, self_value); - let id = spanned(ident_span.lo, ident_span.hi, ident); + let id = respan(ident_span.to(ident_span), ident); let nd = self.mk_method_call(id, tys, es); - self.mk_expr(lo, hi, nd, ThinVec::new()) + self.mk_expr(lo.to(hi), nd, ThinVec::new()) } // Field access. _ => { @@ -2456,32 +2447,30 @@ impl<'a> Parser<'a> { have type parameters"); } - let id = spanned(ident_span.lo, ident_span.hi, ident); + let id = respan(ident_span.to(ident_span), ident); let field = self.mk_field(self_value, id); - self.mk_expr(lo, ident_span.hi, field, ThinVec::new()) + self.mk_expr(lo.to(ident_span), field, ThinVec::new()) } }) } - fn parse_dot_or_call_expr_with_(&mut self, e0: P, lo: BytePos) -> PResult<'a, P> { + fn parse_dot_or_call_expr_with_(&mut self, e0: P, lo: Span) -> PResult<'a, P> { let mut e = e0; let mut hi; loop { // expr? while self.eat(&token::Question) { - let hi = self.prev_span.hi; - e = self.mk_expr(lo, hi, ExprKind::Try(e), ThinVec::new()); + let hi = self.prev_span; + e = self.mk_expr(lo.to(hi), ExprKind::Try(e), ThinVec::new()); } // expr.f if self.eat(&token::Dot) { match self.token { token::Ident(i) => { - let dot_pos = self.prev_span.hi; - hi = self.span.hi; + let ident_span = self.span; self.bump(); - - e = self.parse_dot_suffix(i, mk_sp(dot_pos, hi), e, lo)?; + e = self.parse_dot_suffix(i, ident_span, e, lo)?; } token::Literal(token::Integer(n), suf) => { let sp = self.span; @@ -2489,16 +2478,16 @@ impl<'a> Parser<'a> { // A tuple index may not have a suffix self.expect_no_suffix(sp, "tuple index", suf); - let dot = self.prev_span.hi; - hi = self.span.hi; + let dot_span = self.prev_span; + hi = self.span; self.bump(); let index = n.as_str().parse::().ok(); match index { Some(n) => { - let id = spanned(dot, hi, n); + let id = respan(dot_span.to(hi), n); let field = self.mk_tup_field(e, id); - e = self.mk_expr(lo, hi, field, ThinVec::new()); + e = self.mk_expr(lo.to(hi), field, ThinVec::new()); } None => { let prev_span = self.prev_span; @@ -2541,10 +2530,8 @@ impl<'a> Parser<'a> { let actual = self.this_token_to_string(); self.span_err(self.span, &format!("unexpected token: `{}`", actual)); - let dot_pos = self.prev_span.hi; - e = self.parse_dot_suffix(keywords::Invalid.ident(), - mk_sp(dot_pos, dot_pos), - e, lo)?; + let dot_span = self.prev_span; + e = self.parse_dot_suffix(keywords::Invalid.ident(), dot_span, e, lo)?; } } continue; @@ -2559,10 +2546,10 @@ impl<'a> Parser<'a> { SeqSep::trailing_allowed(token::Comma), |p| Ok(p.parse_expr()?) )?; - hi = self.prev_span.hi; + hi = self.prev_span; let nd = self.mk_call(e, es); - e = self.mk_expr(lo, hi, nd, ThinVec::new()); + e = self.mk_expr(lo.to(hi), nd, ThinVec::new()); } // expr[...] @@ -2570,10 +2557,10 @@ impl<'a> Parser<'a> { token::OpenDelim(token::Bracket) => { self.bump(); let ix = self.parse_expr()?; - hi = self.span.hi; + hi = self.span; self.expect(&token::CloseDelim(token::Bracket))?; let index = self.mk_index(e, ix); - e = self.mk_expr(lo, hi, index, ThinVec::new()) + e = self.mk_expr(lo.to(hi), index, ThinVec::new()) } _ => return Ok(e) } @@ -2635,38 +2622,33 @@ impl<'a> Parser<'a> { already_parsed_attrs: Option>) -> PResult<'a, P> { let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; - let lo = self.span.lo; - let hi; + let lo = self.span; // Note: when adding new unary operators, don't forget to adjust Token::can_begin_expr() - let ex = match self.token { + let (hi, ex) = match self.token { token::Not => { self.bump(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - self.mk_unary(UnOp::Not, e) + (span, self.mk_unary(UnOp::Not, e)) } token::BinOp(token::Minus) => { self.bump(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - self.mk_unary(UnOp::Neg, e) + (span, self.mk_unary(UnOp::Neg, e)) } token::BinOp(token::Star) => { self.bump(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - self.mk_unary(UnOp::Deref, e) + (span, self.mk_unary(UnOp::Deref, e)) } token::BinOp(token::And) | token::AndAnd => { self.expect_and()?; let m = self.parse_mutability(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - ExprKind::AddrOf(m, e) + (span, ExprKind::AddrOf(m, e)) } token::Ident(..) if self.token.is_keyword(keywords::In) => { self.bump(); @@ -2676,20 +2658,18 @@ impl<'a> Parser<'a> { )?; let blk = self.parse_block()?; let span = blk.span; - hi = span.hi; - let blk_expr = self.mk_expr(span.lo, hi, ExprKind::Block(blk), ThinVec::new()); - ExprKind::InPlace(place, blk_expr) + let blk_expr = self.mk_expr(span, ExprKind::Block(blk), ThinVec::new()); + (span, ExprKind::InPlace(place, blk_expr)) } token::Ident(..) if self.token.is_keyword(keywords::Box) => { self.bump(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - ExprKind::Box(e) + (span, ExprKind::Box(e)) } _ => return self.parse_dot_or_call_expr(Some(attrs)) }; - return Ok(self.mk_expr(lo, hi, ex, attrs)); + return Ok(self.mk_expr(lo.to(hi), ex, attrs)); } /// Parse an associative expression @@ -2750,13 +2730,11 @@ impl<'a> Parser<'a> { // Special cases: if op == AssocOp::As { let rhs = self.parse_ty_no_plus()?; - let (lo, hi) = (lhs_span.lo, rhs.span.hi); - lhs = self.mk_expr(lo, hi, ExprKind::Cast(lhs, rhs), ThinVec::new()); + lhs = self.mk_expr(lhs_span.to(rhs.span), ExprKind::Cast(lhs, rhs), ThinVec::new()); continue } else if op == AssocOp::Colon { let rhs = self.parse_ty_no_plus()?; - let (lo, hi) = (lhs_span.lo, rhs.span.hi); - lhs = self.mk_expr(lo, hi, ExprKind::Type(lhs, rhs), ThinVec::new()); + lhs = self.mk_expr(lhs_span.to(rhs.span), ExprKind::Type(lhs, rhs), ThinVec::new()); continue } else if op == AssocOp::DotDot || op == AssocOp::DotDotDot { // If we didn’t have to handle `x..`/`x...`, it would be pretty easy to @@ -2782,7 +2760,7 @@ impl<'a> Parser<'a> { }; let r = try!(self.mk_range(Some(lhs), rhs, limits)); - lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, ThinVec::new()); + lhs = self.mk_expr(lhs_span.to(rhs_span), r, ThinVec::new()); break } @@ -2809,7 +2787,7 @@ impl<'a> Parser<'a> { }), }?; - let (lo, hi) = (lhs_span.lo, rhs.span.hi); + let span = lhs_span.to(rhs.span); lhs = match op { AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus | AssocOp::LAnd | AssocOp::LOr | AssocOp::BitXor | @@ -2818,12 +2796,12 @@ impl<'a> Parser<'a> { AssocOp::Greater | AssocOp::GreaterEqual => { let ast_op = op.to_ast_binop().unwrap(); let binary = self.mk_binary(codemap::respan(cur_op_span, ast_op), lhs, rhs); - self.mk_expr(lo, hi, binary, ThinVec::new()) + self.mk_expr(span, binary, ThinVec::new()) } AssocOp::Assign => - self.mk_expr(lo, hi, ExprKind::Assign(lhs, rhs), ThinVec::new()), + self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()), AssocOp::Inplace => - self.mk_expr(lo, hi, ExprKind::InPlace(lhs, rhs), ThinVec::new()), + self.mk_expr(span, ExprKind::InPlace(lhs, rhs), ThinVec::new()), AssocOp::AssignOp(k) => { let aop = match k { token::Plus => BinOpKind::Add, @@ -2838,7 +2816,7 @@ impl<'a> Parser<'a> { token::Shr => BinOpKind::Shr, }; let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs); - self.mk_expr(lo, hi, aopexpr, ThinVec::new()) + self.mk_expr(span, aopexpr, ThinVec::new()) } AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotDot => { self.bug("As, Colon, DotDot or DotDotDot branch reached") @@ -2858,7 +2836,7 @@ impl<'a> Parser<'a> { match lhs.node { ExprKind::Binary(op, _, _) if op.node.is_comparison() => { // respan to include both operators - let op_span = mk_sp(op.span.lo, self.span.hi); + let op_span = op.span.to(self.span); let mut err = self.diagnostic().struct_span_err(op_span, "chained comparison operators require parentheses"); if op.node == BinOpKind::Lt && @@ -2881,8 +2859,8 @@ impl<'a> Parser<'a> { debug_assert!(self.token == token::DotDot || self.token == token::DotDotDot); let tok = self.token.clone(); let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; - let lo = self.span.lo; - let mut hi = self.span.hi; + let lo = self.span; + let mut hi = self.span; self.bump(); let opt_end = if self.is_at_start_of_range_notation_rhs() { // RHS must be parsed with more associativity than the dots. @@ -2890,7 +2868,7 @@ impl<'a> Parser<'a> { Some(self.parse_assoc_expr_with(next_prec, LhsExpr::NotYetParsed) .map(|x|{ - hi = x.span.hi; + hi = x.span; x })?) } else { @@ -2905,7 +2883,7 @@ impl<'a> Parser<'a> { let r = try!(self.mk_range(None, opt_end, limits)); - Ok(self.mk_expr(lo, hi, r, attrs)) + Ok(self.mk_expr(lo.to(hi), r, attrs)) } fn is_at_start_of_range_notation_rhs(&self) -> bool { @@ -2925,23 +2903,23 @@ impl<'a> Parser<'a> { if self.check_keyword(keywords::Let) { return self.parse_if_let_expr(attrs); } - let lo = self.prev_span.lo; + let lo = self.prev_span; let cond = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; let thn = self.parse_block()?; let mut els: Option> = None; - let mut hi = thn.span.hi; + let mut hi = thn.span; if self.eat_keyword(keywords::Else) { let elexpr = self.parse_else_expr()?; - hi = elexpr.span.hi; + hi = elexpr.span; els = Some(elexpr); } - Ok(self.mk_expr(lo, hi, ExprKind::If(cond, thn, els), attrs)) + Ok(self.mk_expr(lo.to(hi), ExprKind::If(cond, thn, els), attrs)) } /// Parse an 'if let' expression ('if' token already eaten) pub fn parse_if_let_expr(&mut self, attrs: ThinVec) -> PResult<'a, P> { - let lo = self.prev_span.lo; + let lo = self.prev_span; self.expect_keyword(keywords::Let)?; let pat = self.parse_pat()?; self.expect(&token::Eq)?; @@ -2949,36 +2927,35 @@ impl<'a> Parser<'a> { let thn = self.parse_block()?; let (hi, els) = if self.eat_keyword(keywords::Else) { let expr = self.parse_else_expr()?; - (expr.span.hi, Some(expr)) + (expr.span, Some(expr)) } else { - (thn.span.hi, None) + (thn.span, None) }; - Ok(self.mk_expr(lo, hi, ExprKind::IfLet(pat, expr, thn, els), attrs)) + Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pat, expr, thn, els), attrs)) } // `move |args| expr` pub fn parse_lambda_expr(&mut self, - lo: BytePos, + lo: Span, capture_clause: CaptureBy, attrs: ThinVec) -> PResult<'a, P> { let decl = self.parse_fn_block_decl()?; - let decl_hi = self.prev_span.hi; + let decl_hi = self.prev_span; let body = match decl.output { FunctionRetTy::Default(_) => self.parse_expr()?, _ => { // If an explicit return type is given, require a // block to appear (RFC 968). - let body_lo = self.span.lo; + let body_lo = self.span; self.parse_block_expr(body_lo, BlockCheckMode::Default, ThinVec::new())? } }; Ok(self.mk_expr( - lo, - body.span.hi, - ExprKind::Closure(capture_clause, decl, body, mk_sp(lo, decl_hi)), + lo.to(body.span), + ExprKind::Closure(capture_clause, decl, body, lo.to(decl_hi)), attrs)) } @@ -2988,13 +2965,13 @@ impl<'a> Parser<'a> { return self.parse_if_expr(ThinVec::new()); } else { let blk = self.parse_block()?; - return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprKind::Block(blk), ThinVec::new())); + return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), ThinVec::new())); } } /// Parse a 'for' .. 'in' expression ('for' token already eaten) pub fn parse_for_expr(&mut self, opt_ident: Option, - span_lo: BytePos, + span_lo: Span, mut attrs: ThinVec) -> PResult<'a, P> { // Parse: `for in ` @@ -3004,16 +2981,13 @@ impl<'a> Parser<'a> { let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = self.prev_span.hi; - - Ok(self.mk_expr(span_lo, hi, - ExprKind::ForLoop(pat, expr, loop_block, opt_ident), - attrs)) + let hi = self.prev_span; + Ok(self.mk_expr(span_lo.to(hi), ExprKind::ForLoop(pat, expr, loop_block, opt_ident), attrs)) } /// Parse a 'while' or 'while let' expression ('while' token already eaten) pub fn parse_while_expr(&mut self, opt_ident: Option, - span_lo: BytePos, + span_lo: Span, mut attrs: ThinVec) -> PResult<'a, P> { if self.token.is_keyword(keywords::Let) { return self.parse_while_let_expr(opt_ident, span_lo, attrs); @@ -3021,14 +2995,13 @@ impl<'a> Parser<'a> { let cond = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = body.span.hi; - return Ok(self.mk_expr(span_lo, hi, ExprKind::While(cond, body, opt_ident), - attrs)); + let span = span_lo.to(body.span); + return Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_ident), attrs)); } /// Parse a 'while let' expression ('while' token already eaten) pub fn parse_while_let_expr(&mut self, opt_ident: Option, - span_lo: BytePos, + span_lo: Span, mut attrs: ThinVec) -> PResult<'a, P> { self.expect_keyword(keywords::Let)?; let pat = self.parse_pat()?; @@ -3036,34 +3009,33 @@ impl<'a> Parser<'a> { let expr = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = body.span.hi; - return Ok(self.mk_expr(span_lo, hi, ExprKind::WhileLet(pat, expr, body, opt_ident), attrs)); + let span = span_lo.to(body.span); + return Ok(self.mk_expr(span, ExprKind::WhileLet(pat, expr, body, opt_ident), attrs)); } // parse `loop {...}`, `loop` token already eaten pub fn parse_loop_expr(&mut self, opt_ident: Option, - span_lo: BytePos, + span_lo: Span, mut attrs: ThinVec) -> PResult<'a, P> { let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = body.span.hi; - Ok(self.mk_expr(span_lo, hi, ExprKind::Loop(body, opt_ident), attrs)) + let span = span_lo.to(body.span); + Ok(self.mk_expr(span, ExprKind::Loop(body, opt_ident), attrs)) } /// Parse a `do catch {...}` expression (`do catch` token already eaten) - pub fn parse_catch_expr(&mut self, span_lo: BytePos, mut attrs: ThinVec) + pub fn parse_catch_expr(&mut self, span_lo: Span, mut attrs: ThinVec) -> PResult<'a, P> { let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = body.span.hi; - Ok(self.mk_expr(span_lo, hi, ExprKind::Catch(body), attrs)) + Ok(self.mk_expr(span_lo.to(body.span), ExprKind::Catch(body), attrs)) } // `match` token already eaten fn parse_match_expr(&mut self, mut attrs: ThinVec) -> PResult<'a, P> { let match_span = self.prev_span; - let lo = self.prev_span.lo; + let lo = self.prev_span; let discriminant = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) { @@ -3082,17 +3054,17 @@ impl<'a> Parser<'a> { // Recover by skipping to the end of the block. e.emit(); self.recover_stmt(); - let hi = self.span.hi; + let span = lo.to(self.span); if self.token == token::CloseDelim(token::Brace) { self.bump(); } - return Ok(self.mk_expr(lo, hi, ExprKind::Match(discriminant, arms), attrs)); + return Ok(self.mk_expr(span, ExprKind::Match(discriminant, arms), attrs)); } } } - let hi = self.span.hi; + let hi = self.span; self.bump(); - return Ok(self.mk_expr(lo, hi, ExprKind::Match(discriminant, arms), attrs)); + return Ok(self.mk_expr(lo.to(hi), ExprKind::Match(discriminant, arms), attrs)); } pub fn parse_arm(&mut self) -> PResult<'a, Arm> { @@ -3266,7 +3238,7 @@ impl<'a> Parser<'a> { } let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; let hi; if self.check(&token::DotDot) { @@ -3286,16 +3258,16 @@ impl<'a> Parser<'a> { let fieldname = self.parse_field_name()?; self.bump(); let pat = self.parse_pat()?; - hi = pat.span.hi; + hi = pat.span; (pat, fieldname, false) } else { // Parsing a pattern of the form "(box) (ref) (mut) fieldname" let is_box = self.eat_keyword(keywords::Box); - let boxed_span_lo = self.span.lo; + let boxed_span = self.span; let is_ref = self.eat_keyword(keywords::Ref); let is_mut = self.eat_keyword(keywords::Mut); let fieldname = self.parse_ident()?; - hi = self.prev_span.hi; + hi = self.prev_span; let bind_type = match (is_ref, is_mut) { (true, true) => BindingMode::ByRef(Mutability::Mutable), @@ -3307,14 +3279,14 @@ impl<'a> Parser<'a> { let fieldpat = P(ast::Pat{ id: ast::DUMMY_NODE_ID, node: PatKind::Ident(bind_type, fieldpath, None), - span: mk_sp(boxed_span_lo, hi), + span: boxed_span.to(hi), }); let subpat = if is_box { P(ast::Pat{ id: ast::DUMMY_NODE_ID, node: PatKind::Box(fieldpat), - span: mk_sp(lo, hi), + span: lo.to(hi), }) } else { fieldpat @@ -3322,7 +3294,7 @@ impl<'a> Parser<'a> { (subpat, fieldname, true) }; - fields.push(codemap::Spanned { span: mk_sp(lo, hi), + fields.push(codemap::Spanned { span: lo.to(hi), node: ast::FieldPat { ident: fieldname, pat: subpat, @@ -3336,7 +3308,7 @@ impl<'a> Parser<'a> { fn parse_pat_range_end(&mut self) -> PResult<'a, P> { if self.token.is_path_start() { - let lo = self.span.lo; + let lo = self.span; let (qself, path) = if self.eat_lt() { // Parse a qualified path let (qself, path) = @@ -3346,8 +3318,8 @@ impl<'a> Parser<'a> { // Parse an unqualified path (None, self.parse_path(PathStyle::Expr)?) }; - let hi = self.prev_span.hi; - Ok(self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new())) + let hi = self.prev_span; + Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path), ThinVec::new())) } else { self.parse_pat_literal_maybe_minus() } @@ -3373,7 +3345,7 @@ impl<'a> Parser<'a> { pub fn parse_pat(&mut self) -> PResult<'a, P> { maybe_whole!(self, NtPat, |x| x); - let lo = self.span.lo; + let lo = self.span; let pat; match self.token { token::Underscore => { @@ -3439,7 +3411,7 @@ impl<'a> Parser<'a> { // Parse macro invocation self.bump(); let (_, tts) = self.expect_delimited_token_tree()?; - let mac = spanned(lo, self.prev_span.hi, Mac_ { path: path, tts: tts }); + let mac = respan(lo.to(self.prev_span), Mac_ { path: path, tts: tts }); pat = PatKind::Mac(mac); } token::DotDotDot | token::DotDot => { @@ -3449,9 +3421,8 @@ impl<'a> Parser<'a> { _ => panic!("can only parse `..` or `...` for ranges (checked above)"), }; // Parse range - let hi = self.prev_span.hi; - let begin = - self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new()); + let span = lo.to(self.prev_span); + let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new()); self.bump(); let end = self.parse_pat_range_end()?; pat = PatKind::Range(begin, end, end_kind); @@ -3505,11 +3476,10 @@ impl<'a> Parser<'a> { } } - let hi = self.prev_span.hi; Ok(P(ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, - span: mk_sp(lo, hi), + span: lo.to(self.prev_span), })) } @@ -3545,7 +3515,7 @@ impl<'a> Parser<'a> { /// Parse a local variable declaration fn parse_local(&mut self, attrs: ThinVec) -> PResult<'a, P> { - let lo = self.span.lo; + let lo = self.span; let pat = self.parse_pat()?; let mut ty = None; @@ -3558,14 +3528,14 @@ impl<'a> Parser<'a> { pat: pat, init: init, id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), attrs: attrs, })) } /// Parse a structure field fn parse_name_and_ty(&mut self, - lo: BytePos, + lo: Span, vis: Visibility, attrs: Vec) -> PResult<'a, StructField> { @@ -3573,7 +3543,7 @@ impl<'a> Parser<'a> { self.expect(&token::Colon)?; let ty = self.parse_ty()?; Ok(StructField { - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), ident: Some(name), vis: vis, id: ast::DUMMY_NODE_ID, @@ -3683,7 +3653,7 @@ impl<'a> Parser<'a> { fn eat_macro_def(&mut self, attrs: &[Attribute], vis: &Visibility) -> PResult<'a, Option>> { - let lo = self.span.lo; + let lo = self.span; match self.token { token::Ident(ident) if ident.name == "macro_rules" => { if self.look_ahead(1, |t| *t == token::Not) { @@ -3706,9 +3676,9 @@ impl<'a> Parser<'a> { } } - let hi = self.prev_span.hi; + let span = lo.to(self.prev_span); let kind = ItemKind::MacroDef(tts); - Ok(Some(self.mk_item(lo, hi, id, kind, Visibility::Inherited, attrs.to_owned()))) + Ok(Some(self.mk_item(span, id, kind, Visibility::Inherited, attrs.to_owned()))) } fn parse_stmt_without_recovery(&mut self, @@ -3717,19 +3687,19 @@ impl<'a> Parser<'a> { maybe_whole!(self, NtStmt, |x| Some(x)); let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; Ok(Some(if self.eat_keyword(keywords::Let) { Stmt { id: ast::DUMMY_NODE_ID, node: StmtKind::Local(self.parse_local(attrs.into())?), - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), } } else if let Some(macro_def) = self.eat_macro_def(&attrs, &Visibility::Inherited)? { Stmt { id: ast::DUMMY_NODE_ID, node: StmtKind::Item(macro_def), - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), } // Starts like a simple path, but not a union item. } else if self.token.is_path_start() && @@ -3741,8 +3711,8 @@ impl<'a> Parser<'a> { let expr = if self.check(&token::OpenDelim(token::Brace)) { self.parse_struct_expr(lo, pth, ThinVec::new())? } else { - let hi = self.prev_span.hi; - self.mk_expr(lo, hi, ExprKind::Path(None, pth), ThinVec::new()) + let hi = self.prev_span; + self.mk_expr(lo.to(hi), ExprKind::Path(None, pth), ThinVec::new()) }; let expr = self.with_res(Restrictions::RESTRICTION_STMT_EXPR, |this| { @@ -3753,7 +3723,7 @@ impl<'a> Parser<'a> { return Ok(Some(Stmt { id: ast::DUMMY_NODE_ID, node: StmtKind::Expr(expr), - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), })); } @@ -3784,7 +3754,7 @@ impl<'a> Parser<'a> { }; let (_, tts) = self.expect_delimited_token_tree()?; - let hi = self.prev_span.hi; + let hi = self.prev_span; let style = if delim == token::Brace { MacStmtStyle::Braces @@ -3793,7 +3763,7 @@ impl<'a> Parser<'a> { }; if id.name == keywords::Invalid.name() { - let mac = spanned(lo, hi, Mac_ { path: pth, tts: tts }); + let mac = respan(lo.to(hi), Mac_ { path: pth, tts: tts }); let node = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof { StmtKind::Mac(P((mac, style, attrs.into()))) @@ -3813,14 +3783,14 @@ impl<'a> Parser<'a> { self.warn_missing_semicolon(); StmtKind::Mac(P((mac, style, attrs.into()))) } else { - let e = self.mk_mac_expr(lo, hi, mac.node, ThinVec::new()); + let e = self.mk_mac_expr(lo.to(hi), mac.node, ThinVec::new()); let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?; let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; StmtKind::Expr(e) }; Stmt { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), + span: lo.to(hi), node: node, } } else { @@ -3835,13 +3805,14 @@ impl<'a> Parser<'a> { followed by a semicolon"); } } + let span = lo.to(hi); Stmt { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), + span: span, node: StmtKind::Item({ self.mk_item( - lo, hi, id /*id is good here*/, - ItemKind::Mac(spanned(lo, hi, Mac_ { path: pth, tts: tts })), + span, id /*id is good here*/, + ItemKind::Mac(respan(span, Mac_ { path: pth, tts: tts })), Visibility::Inherited, attrs) }), @@ -3856,7 +3827,7 @@ impl<'a> Parser<'a> { match item { Some(i) => Stmt { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, i.span.hi), + span: lo.to(i.span), node: StmtKind::Item(i), }, None => { @@ -3887,7 +3858,7 @@ impl<'a> Parser<'a> { Restrictions::RESTRICTION_STMT_EXPR, Some(attrs.into()))?; Stmt { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, e.span.hi), + span: lo.to(e.span), node: StmtKind::Expr(e), } } @@ -3905,7 +3876,7 @@ impl<'a> Parser<'a> { pub fn parse_block(&mut self) -> PResult<'a, P> { maybe_whole!(self, NtBlock, |x| x); - let lo = self.span.lo; + let lo = self.span; if !self.eat(&token::OpenDelim(token::Brace)) { let sp = self.span; @@ -3950,7 +3921,7 @@ impl<'a> Parser<'a> { fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (Vec, P)> { maybe_whole!(self, NtBlock, |x| (Vec::new(), x)); - let lo = self.span.lo; + let lo = self.span; self.expect(&token::OpenDelim(token::Brace))?; Ok((self.parse_inner_attributes()?, self.parse_block_tail(lo, BlockCheckMode::Default)?)) @@ -3958,7 +3929,7 @@ impl<'a> Parser<'a> { /// Parse the rest of a block expression or function body /// Precondition: already parsed the '{'. - fn parse_block_tail(&mut self, lo: BytePos, s: BlockCheckMode) -> PResult<'a, P> { + fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) -> PResult<'a, P> { let mut stmts = vec![]; while !self.eat(&token::CloseDelim(token::Brace)) { @@ -3976,7 +3947,7 @@ impl<'a> Parser<'a> { stmts: stmts, id: ast::DUMMY_NODE_ID, rules: s, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), })) } @@ -4042,10 +4013,10 @@ impl<'a> Parser<'a> { } bounds.push(RegionTyParamBound(self.expect_lifetime())); } else if self.check_keyword(keywords::For) || self.check_path() { - let lo = self.span.lo; + let lo = self.span; let lifetime_defs = self.parse_late_bound_lifetime_defs()?; let path = self.parse_path(PathStyle::Type)?; - let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo, self.prev_span.hi); + let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); let modifier = if question.is_some() { TraitBoundModifier::Maybe } else { @@ -4166,7 +4137,7 @@ impl<'a> Parser<'a> { pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> { maybe_whole!(self, NtGenerics, |x| x); - let span_lo = self.span.lo; + let span_lo = self.span; if self.eat_lt() { let (lifetime_defs, ty_params) = self.parse_generic_params()?; self.expect_gt()?; @@ -4177,7 +4148,7 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), }, - span: mk_sp(span_lo, self.prev_span.hi), + span: span_lo.to(self.prev_span), }) } else { Ok(ast::Generics::default()) @@ -4202,7 +4173,7 @@ impl<'a> Parser<'a> { } } else if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) { // Parse associated type binding. - let lo = self.span.lo; + let lo = self.span; let ident = self.parse_ident()?; self.bump(); let ty = self.parse_ty()?; @@ -4210,7 +4181,7 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, ident: ident, ty: ty, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), }); seen_binding = true; } else if self.check_type() { @@ -4267,7 +4238,7 @@ impl<'a> Parser<'a> { } loop { - let lo = self.span.lo; + let lo = self.span; if self.check_lifetime() && self.look_ahead(1, |t| t != &token::BinOp(token::Plus)) { let lifetime = self.expect_lifetime(); // Bounds starting with a colon are mandatory, but possibly empty. @@ -4275,7 +4246,7 @@ impl<'a> Parser<'a> { let bounds = self.parse_lt_param_bounds(); where_clause.predicates.push(ast::WherePredicate::RegionPredicate( ast::WhereRegionPredicate { - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), lifetime: lifetime, bounds: bounds, } @@ -4296,7 +4267,7 @@ impl<'a> Parser<'a> { let bounds = self.parse_ty_param_bounds()?; where_clause.predicates.push(ast::WherePredicate::BoundPredicate( ast::WhereBoundPredicate { - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), bound_lifetimes: lifetime_defs, bounded_ty: ty, bounds: bounds, @@ -4307,7 +4278,7 @@ impl<'a> Parser<'a> { let rhs_ty = self.parse_ty()?; where_clause.predicates.push(ast::WherePredicate::EqPredicate( ast::WhereEqPredicate { - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), lhs_ty: ty, rhs_ty: rhs_ty, id: ast::DUMMY_NODE_ID, @@ -4404,7 +4375,7 @@ impl<'a> Parser<'a> { // Parse optional self parameter of a method. // Only a limited set of initial token sequences is considered self parameters, anything // else is parsed as a normal function parameter list, so some lookahead is required. - let eself_lo = self.span.lo; + let eself_lo = self.span; let (eself, eself_ident) = match self.token { token::BinOp(token::And) => { // &self @@ -4486,7 +4457,7 @@ impl<'a> Parser<'a> { _ => return Ok(None), }; - let eself = codemap::respan(mk_sp(eself_lo, self.prev_span.hi), eself); + let eself = codemap::respan(eself_lo.to(self.prev_span), eself); Ok(Some(Arg::from_self(eself, eself_ident))) } @@ -4558,8 +4529,7 @@ impl<'a> Parser<'a> { Ok((id, generics)) } - fn mk_item(&mut self, lo: BytePos, hi: BytePos, ident: Ident, - node: ItemKind, vis: Visibility, + fn mk_item(&mut self, span: Span, ident: Ident, node: ItemKind, vis: Visibility, attrs: Vec) -> P { P(Item { ident: ident, @@ -4567,7 +4537,7 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, node: node, vis: vis, - span: mk_sp(lo, hi) + span: span, }) } @@ -4625,7 +4595,7 @@ impl<'a> Parser<'a> { maybe_whole!(self, NtImplItem, |x| x); let mut attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; let vis = self.parse_visibility(false)?; let defaultness = self.parse_defaultness()?; let (name, node) = if self.eat_keyword(keywords::Type) { @@ -4651,7 +4621,7 @@ impl<'a> Parser<'a> { Ok(ImplItem { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), ident: name, vis: vis, defaultness: defaultness, @@ -4694,7 +4664,7 @@ impl<'a> Parser<'a> { let prev_span = self.prev_span; self.complain_if_pub_macro(&vis, prev_span); - let lo = self.span.lo; + let lo = self.span; let pth = self.parse_path(PathStyle::Mod)?; self.expect(&token::Not)?; @@ -4704,7 +4674,7 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)? } - let mac = spanned(lo, self.prev_span.hi, Mac_ { path: pth, tts: tts }); + let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts }); Ok((keywords::Invalid.ident(), vec![], ast::ImplItemKind::Macro(mac))) } else { let (constness, unsafety, abi) = self.parse_fn_front_matter()?; @@ -4938,11 +4908,11 @@ impl<'a> Parser<'a> { SeqSep::trailing_allowed(token::Comma), |p| { let attrs = p.parse_outer_attributes()?; - let lo = p.span.lo; + let lo = p.span; let vis = p.parse_visibility(true)?; let ty = p.parse_ty()?; Ok(StructField { - span: mk_sp(lo, p.span.hi), + span: lo.to(p.span), vis: vis, ident: None, id: ast::DUMMY_NODE_ID, @@ -4956,7 +4926,7 @@ impl<'a> Parser<'a> { /// Parse a structure field declaration pub fn parse_single_struct_field(&mut self, - lo: BytePos, + lo: Span, vis: Visibility, attrs: Vec ) -> PResult<'a, StructField> { @@ -4978,7 +4948,7 @@ impl<'a> Parser<'a> { /// Parse an element of a struct definition fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> { let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; let vis = self.parse_visibility(false)?; self.parse_single_struct_field(lo, vis, attrs) } @@ -5056,7 +5026,7 @@ impl<'a> Parser<'a> { } /// Given a termination token, parse all of the items in a module - fn parse_mod_items(&mut self, term: &token::Token, inner_lo: BytePos) -> PResult<'a, Mod> { + fn parse_mod_items(&mut self, term: &token::Token, inner_lo: Span) -> PResult<'a, Mod> { let mut items = vec![]; while let Some(item) = self.parse_item()? { items.push(item); @@ -5070,11 +5040,11 @@ impl<'a> Parser<'a> { let hi = if self.span == syntax_pos::DUMMY_SP { inner_lo } else { - self.prev_span.hi + self.prev_span }; Ok(ast::Mod { - inner: mk_sp(inner_lo, hi), + inner: inner_lo.to(hi), items: items }) } @@ -5137,7 +5107,7 @@ impl<'a> Parser<'a> { let old_directory = self.directory.clone(); self.push_directory(id, &outer_attrs); self.expect(&token::OpenDelim(token::Brace))?; - let mod_inner_lo = self.span.lo; + let mod_inner_lo = self.span; let attrs = self.parse_inner_attributes()?; let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?; self.directory = old_directory; @@ -5280,7 +5250,7 @@ impl<'a> Parser<'a> { let mut p0 = new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp); p0.cfg_mods = self.cfg_mods; - let mod_inner_lo = p0.span.lo; + let mod_inner_lo = p0.span; let mod_attrs = p0.parse_inner_attributes()?; let m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo)?; self.sess.included_mod_stack.borrow_mut().pop(); @@ -5288,42 +5258,42 @@ impl<'a> Parser<'a> { } /// Parse a function declaration from a foreign module - fn parse_item_foreign_fn(&mut self, vis: ast::Visibility, lo: BytePos, - attrs: Vec) -> PResult<'a, ForeignItem> { + fn parse_item_foreign_fn(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec) + -> PResult<'a, ForeignItem> { self.expect_keyword(keywords::Fn)?; let (ident, mut generics) = self.parse_fn_header()?; let decl = self.parse_fn_decl(true)?; generics.where_clause = self.parse_where_clause()?; - let hi = self.span.hi; + let hi = self.span; self.expect(&token::Semi)?; Ok(ast::ForeignItem { ident: ident, attrs: attrs, node: ForeignItemKind::Fn(decl, generics), id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), + span: lo.to(hi), vis: vis }) } /// Parse a static item from a foreign module - fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: BytePos, - attrs: Vec) -> PResult<'a, ForeignItem> { + fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec) + -> PResult<'a, ForeignItem> { self.expect_keyword(keywords::Static)?; let mutbl = self.eat_keyword(keywords::Mut); let ident = self.parse_ident()?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; - let hi = self.span.hi; + let hi = self.span; self.expect(&token::Semi)?; Ok(ForeignItem { ident: ident, attrs: attrs, node: ForeignItemKind::Static(ty, mutbl), id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), + span: lo.to(hi), vis: vis }) } @@ -5335,7 +5305,7 @@ impl<'a> Parser<'a> { /// extern crate foo; /// extern crate bar as foo; fn parse_item_extern_crate(&mut self, - lo: BytePos, + lo: Span, visibility: Visibility, attrs: Vec) -> PResult<'a, P> { @@ -5349,8 +5319,7 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)?; let prev_span = self.prev_span; - Ok(self.mk_item(lo, - prev_span.hi, + Ok(self.mk_item(lo.to(prev_span), ident, ItemKind::ExternCrate(maybe_path), visibility, @@ -5368,7 +5337,7 @@ impl<'a> Parser<'a> { /// extern "C" {} /// extern {} fn parse_item_foreign_mod(&mut self, - lo: BytePos, + lo: Span, opt_abi: Option, visibility: Visibility, mut attrs: Vec) @@ -5390,12 +5359,8 @@ impl<'a> Parser<'a> { abi: abi, items: foreign_items }; - Ok(self.mk_item(lo, - prev_span.hi, - keywords::Invalid.ident(), - ItemKind::ForeignMod(m), - visibility, - attrs)) + let invalid = keywords::Invalid.ident(); + Ok(self.mk_item(lo.to(prev_span), invalid, ItemKind::ForeignMod(m), visibility, attrs)) } /// Parse type Foo = Bar; @@ -5416,7 +5381,7 @@ impl<'a> Parser<'a> { let mut any_disr = None; while self.token != token::CloseDelim(token::Brace) { let variant_attrs = self.parse_outer_attributes()?; - let vlo = self.span.lo; + let vlo = self.span; let struct_def; let mut disr_expr = None; @@ -5444,7 +5409,7 @@ impl<'a> Parser<'a> { data: struct_def, disr_expr: disr_expr, }; - variants.push(spanned(vlo, self.prev_span.hi, vr)); + variants.push(respan(vlo.to(self.prev_span), vr)); if !self.eat(&token::Comma) { break; } } @@ -5514,7 +5479,7 @@ impl<'a> Parser<'a> { Some(P(item)) }); - let lo = self.span.lo; + let lo = self.span; let visibility = self.parse_visibility(false)?; @@ -5524,12 +5489,8 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, - keywords::Invalid.ident(), - item_, - visibility, - attrs); + let invalid = keywords::Invalid.ident(); + let item = self.mk_item(lo.to(prev_span), invalid, item_, visibility, attrs); return Ok(Some(item)); } @@ -5549,8 +5510,7 @@ impl<'a> Parser<'a> { respan(fn_span, Constness::NotConst), abi)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5572,8 +5532,7 @@ impl<'a> Parser<'a> { }; let (ident, item_, extra_attrs) = self.parse_item_const(Some(m))?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5597,8 +5556,7 @@ impl<'a> Parser<'a> { respan(const_span, Constness::Const), Abi::Rust)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5615,8 +5573,7 @@ impl<'a> Parser<'a> { } let (ident, item_, extra_attrs) = self.parse_item_const(None)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5632,8 +5589,7 @@ impl<'a> Parser<'a> { let (ident, item_, extra_attrs) = self.parse_item_trait(ast::Unsafety::Unsafe)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5648,8 +5604,7 @@ impl<'a> Parser<'a> { self.expect_keyword(keywords::Impl)?; let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5665,8 +5620,7 @@ impl<'a> Parser<'a> { respan(fn_span, Constness::NotConst), Abi::Rust)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5689,8 +5643,7 @@ impl<'a> Parser<'a> { respan(fn_span, Constness::NotConst), abi)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5702,8 +5655,7 @@ impl<'a> Parser<'a> { let (ident, item_, extra_attrs) = self.parse_item_mod(&attrs[..])?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5714,8 +5666,7 @@ impl<'a> Parser<'a> { // TYPE ITEM let (ident, item_, extra_attrs) = self.parse_item_type()?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5726,8 +5677,7 @@ impl<'a> Parser<'a> { // ENUM ITEM let (ident, item_, extra_attrs) = self.parse_item_enum()?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5739,8 +5689,7 @@ impl<'a> Parser<'a> { let (ident, item_, extra_attrs) = self.parse_item_trait(ast::Unsafety::Normal)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5751,8 +5700,7 @@ impl<'a> Parser<'a> { // IMPL ITEM let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5763,8 +5711,7 @@ impl<'a> Parser<'a> { // STRUCT ITEM let (ident, item_, extra_attrs) = self.parse_item_struct()?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5776,8 +5723,7 @@ impl<'a> Parser<'a> { self.bump(); let (ident, item_, extra_attrs) = self.parse_item_union()?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5794,7 +5740,7 @@ impl<'a> Parser<'a> { /// Parse a foreign item. fn parse_foreign_item(&mut self) -> PResult<'a, Option> { let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; let visibility = self.parse_visibility(false)?; if self.check_keyword(keywords::Static) { @@ -5821,7 +5767,7 @@ impl<'a> Parser<'a> { attrs: Vec , macros_allowed: bool, attributes_allowed: bool, - lo: BytePos, + lo: Span, visibility: Visibility ) -> PResult<'a, Option>> { if macros_allowed && self.token.is_path_start() { @@ -5830,7 +5776,7 @@ impl<'a> Parser<'a> { let prev_span = self.prev_span; self.complain_if_pub_macro(&visibility, prev_span); - let mac_lo = self.span.lo; + let mac_lo = self.span; // item macro. let pth = self.parse_path(PathStyle::Mod)?; @@ -5856,9 +5802,9 @@ impl<'a> Parser<'a> { } } - let hi = self.prev_span.hi; - let mac = spanned(mac_lo, hi, Mac_ { path: pth, tts: tts }); - let item = self.mk_item(lo, hi, id, ItemKind::Mac(mac), visibility, attrs); + let hi = self.prev_span; + let mac = respan(mac_lo.to(hi), Mac_ { path: pth, tts: tts }); + let item = self.mk_item(lo.to(hi), id, ItemKind::Mac(mac), visibility, attrs); return Ok(Some(item)); } @@ -5886,7 +5832,7 @@ impl<'a> Parser<'a> { self.parse_unspanned_seq(&token::OpenDelim(token::Brace), &token::CloseDelim(token::Brace), SeqSep::trailing_allowed(token::Comma), |this| { - let lo = this.span.lo; + let lo = this.span; let ident = if this.eat_keyword(keywords::SelfValue) { keywords::SelfValue.ident() } else { @@ -5898,8 +5844,7 @@ impl<'a> Parser<'a> { rename: rename, id: ast::DUMMY_NODE_ID }; - let hi = this.prev_span.hi; - Ok(spanned(lo, hi, node)) + Ok(respan(lo.to(this.prev_span), node)) }) } @@ -5917,21 +5862,21 @@ impl<'a> Parser<'a> { /// MOD_SEP? non_global_path MOD_SEP LBRACE item_seq RBRACE /// MOD_SEP? LBRACE item_seq RBRACE fn parse_view_path(&mut self) -> PResult<'a, P> { - let lo = self.span.lo; + let lo = self.span; if self.check(&token::OpenDelim(token::Brace)) || self.check(&token::BinOp(token::Star)) || self.is_import_coupler() { // `{foo, bar}`, `::{foo, bar}`, `*`, or `::*`. self.eat(&token::ModSep); let prefix = ast::Path { segments: vec![PathSegment::crate_root()], - span: mk_sp(lo, self.span.hi), + span: lo.to(self.span), }; let view_path_kind = if self.eat(&token::BinOp(token::Star)) { ViewPathGlob(prefix) } else { ViewPathList(prefix, self.parse_path_list_items()?) }; - Ok(P(spanned(lo, self.span.hi, view_path_kind))) + Ok(P(respan(lo.to(self.span), view_path_kind))) } else { let prefix = self.parse_path(PathStyle::Mod)?.default_to_global(); if self.is_import_coupler() { @@ -5939,16 +5884,16 @@ impl<'a> Parser<'a> { self.bump(); if self.check(&token::BinOp(token::Star)) { self.bump(); - Ok(P(spanned(lo, self.span.hi, ViewPathGlob(prefix)))) + Ok(P(respan(lo.to(self.span), ViewPathGlob(prefix)))) } else { let items = self.parse_path_list_items()?; - Ok(P(spanned(lo, self.span.hi, ViewPathList(prefix, items)))) + Ok(P(respan(lo.to(self.span), ViewPathList(prefix, items)))) } } else { // `foo::bar` or `foo::bar as baz` let rename = self.parse_rename()?. unwrap_or(prefix.segments.last().unwrap().identifier); - Ok(P(spanned(lo, self.prev_span.hi, ViewPathSimple(rename, prefix)))) + Ok(P(respan(lo.to(self.prev_span), ViewPathSimple(rename, prefix)))) } } } @@ -5964,11 +5909,11 @@ impl<'a> Parser<'a> { /// Parses a source module as a crate. This is the main /// entry point for the parser. pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> { - let lo = self.span.lo; + let lo = self.span; Ok(ast::Crate { attrs: self.parse_inner_attributes()?, module: self.parse_mod_items(&token::Eof, lo)?, - span: mk_sp(lo, self.span.lo), + span: lo.to(self.span), }) } diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index aeb5b1e0a53..6f5ab50b2fe 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -559,11 +559,7 @@ impl<'a, 'b> Context<'a, 'b> { let name = self.ecx.ident_of(&format!("__arg{}", i)); pats.push(self.ecx.pat_ident(DUMMY_SP, name)); for ref arg_ty in self.arg_unique_types[i].iter() { - locals.push(Context::format_arg(self.ecx, - self.macsp, - e.span, - arg_ty, - self.ecx.expr_ident(e.span, name))); + locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, name)); } heads.push(self.ecx.expr_addr_of(e.span, e)); } @@ -576,11 +572,7 @@ impl<'a, 'b> Context<'a, 'b> { Exact(i) => spans_pos[i], _ => panic!("should never happen"), }; - counts.push(Context::format_arg(self.ecx, - self.macsp, - span, - &Count, - self.ecx.expr_ident(span, name))); + counts.push(Context::format_arg(self.ecx, self.macsp, span, &Count, name)); } // Now create a vector containing all the arguments @@ -643,9 +635,10 @@ impl<'a, 'b> Context<'a, 'b> { macsp: Span, mut sp: Span, ty: &ArgumentType, - arg: P) + arg: ast::Ident) -> P { sp.ctxt = sp.ctxt.apply_mark(ecx.current_expansion.mark); + let arg = ecx.expr_ident(sp, arg); let trait_ = match *ty { Placeholder(ref tyname) => { match &tyname[..] { diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 9b45e364ecf..947192a0a23 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -174,6 +174,15 @@ impl Span { } result } + + pub fn to(self, end: Span) -> Span { + // FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480) + if end.ctxt == SyntaxContext::empty() { + Span { lo: self.lo, ..end } + } else { + Span { hi: end.hi, ..self } + } + } } #[derive(Clone, Debug)] @@ -208,7 +217,7 @@ impl serialize::UseSpecializedDecodable for Span { d.read_struct("Span", 2, |d| { let lo = d.read_struct_field("lo", 0, Decodable::decode)?; let hi = d.read_struct_field("hi", 1, Decodable::decode)?; - Ok(mk_sp(lo, hi)) + Ok(Span { lo: lo, hi: hi, ctxt: NO_EXPANSION }) }) } } @@ -696,11 +705,6 @@ pub struct FileLines { thread_local!(pub static SPAN_DEBUG: Cell fmt::Result> = Cell::new(default_span_debug)); -/* assuming that we're not in macro expansion */ -pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span { - Span {lo: lo, hi: hi, ctxt: NO_EXPANSION} -} - pub struct MacroBacktrace { /// span where macro was applied to generate this code pub call_site: Span, diff --git a/src/test/compile-fail/imports/macro-paths.rs b/src/test/compile-fail/imports/macro-paths.rs index 48e7ca0eee4..7c19917acc4 100644 --- a/src/test/compile-fail/imports/macro-paths.rs +++ b/src/test/compile-fail/imports/macro-paths.rs @@ -25,7 +25,6 @@ fn f() { bar::m! { //~ ERROR ambiguous //~| NOTE macro-expanded items do not shadow when used in a macro invocation path mod bar { pub use two_macros::m; } //~ NOTE could refer to the name defined here - //~^^^ NOTE in this expansion } } @@ -37,6 +36,5 @@ fn g() { baz::m! { //~ ERROR ambiguous //~| NOTE macro-expanded items do not shadow when used in a macro invocation path mod baz { pub use two_macros::m; } //~ NOTE could refer to the name defined here - //~^^^ NOTE in this expansion } } diff --git a/src/test/compile-fail/imports/macros.rs b/src/test/compile-fail/imports/macros.rs index cfa7681dc22..06b0964a3b1 100644 --- a/src/test/compile-fail/imports/macros.rs +++ b/src/test/compile-fail/imports/macros.rs @@ -28,7 +28,6 @@ mod m2 { m! { //~ ERROR ambiguous //~| NOTE macro-expanded macro imports do not shadow use foo::m; //~ NOTE could refer to the name imported here - //~^^^ NOTE in this expansion } } @@ -43,7 +42,6 @@ mod m3 { m! { //~ ERROR ambiguous //~| NOTE macro-expanded macro imports do not shadow use two_macros::n as m; //~ NOTE could refer to the name imported here - //~^^^ NOTE in this expansion } } } diff --git a/src/test/compile-fail/imports/shadow_builtin_macros.rs b/src/test/compile-fail/imports/shadow_builtin_macros.rs index 2b3ba1b4aa7..a7f1cf3c9d3 100644 --- a/src/test/compile-fail/imports/shadow_builtin_macros.rs +++ b/src/test/compile-fail/imports/shadow_builtin_macros.rs @@ -31,7 +31,6 @@ mod m2 { mod m3 { ::two_macros::m!(use foo::panic;); //~ NOTE `panic` could refer to the name imported here - //~| NOTE in this expansion fn f() { panic!(); } //~ ERROR ambiguous //~| NOTE `panic` is also a builtin macro //~| NOTE macro-expanded macro imports do not shadow diff --git a/src/test/compile-fail/issue-25385.rs b/src/test/compile-fail/issue-25385.rs index 51d7baaf3e9..4aacb6840e9 100644 --- a/src/test/compile-fail/issue-25385.rs +++ b/src/test/compile-fail/issue-25385.rs @@ -21,5 +21,4 @@ fn main() { foo!(1i32.foo()); //~^ ERROR no method named `foo` found for type `i32` in the current scope - //~^^ NOTE in this expansion of foo! } diff --git a/src/test/run-pass/syntax-extension-source-utils.rs b/src/test/run-pass/syntax-extension-source-utils.rs index 3b5f033d07b..25c7417f7eb 100644 --- a/src/test/run-pass/syntax-extension-source-utils.rs +++ b/src/test/run-pass/syntax-extension-source-utils.rs @@ -22,7 +22,7 @@ macro_rules! indirect_line { () => ( line!() ) } pub fn main() { assert_eq!(line!(), 24); - assert_eq!(column!(), 4); + assert_eq!(column!(), 15); assert_eq!(indirect_line!(), 26); assert!((file!().ends_with("syntax-extension-source-utils.rs"))); assert_eq!(stringify!((2*3) + 5).to_string(), "( 2 * 3 ) + 5".to_string()); diff --git a/src/test/ui/macros/macro_path_as_generic_bound.stderr b/src/test/ui/macros/macro_path_as_generic_bound.stderr index 96635032105..e4044f5aaf2 100644 --- a/src/test/ui/macros/macro_path_as_generic_bound.stderr +++ b/src/test/ui/macros/macro_path_as_generic_bound.stderr @@ -2,10 +2,7 @@ error[E0433]: failed to resolve. Use of undeclared type or module `m` --> $DIR/macro_path_as_generic_bound.rs:17:6 | 17 | foo!(m::m2::A); - | -----^^^^^^^^-- - | | | - | | Use of undeclared type or module `m` - | in this macro invocation + | ^^^^^^^^ Use of undeclared type or module `m` error: cannot continue compilation due to previous error -- cgit 1.4.1-3-g733a5 From 8fde04b4a295792249d4a01f87a9f66143aa7c83 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 29 Mar 2017 07:17:18 +0000 Subject: Improve `Path` spans. --- src/libsyntax/attr.rs | 7 +++-- src/libsyntax/ext/base.rs | 21 +++++++++++++- src/libsyntax/ext/tt/macro_parser.rs | 2 +- src/libsyntax/ext/tt/macro_rules.rs | 2 +- src/libsyntax/ext/tt/quoted.rs | 13 +++++---- src/libsyntax/ext/tt/transcribe.rs | 9 +----- src/libsyntax/parse/mod.rs | 4 +-- src/libsyntax/parse/parser.rs | 56 ++++++++++++++++++++++-------------- src/libsyntax/parse/token.rs | 48 +++++++++++++++---------------- 9 files changed, 95 insertions(+), 67 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 5dcce2572af..6f5f52ff1e9 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -1015,9 +1015,10 @@ impl MetaItem { { let (mut span, name) = match tokens.next() { Some(TokenTree::Token(span, Token::Ident(ident))) => (span, ident.name), - Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => return match **nt { - token::Nonterminal::NtMeta(ref meta) => Some(meta.clone()), - _ => None, + Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => match **nt { + token::Nonterminal::NtIdent(ident) => (ident.span, ident.node.name), + token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()), + _ => return None, }, _ => return None, }; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index a2d54b62ec6..fda026fec64 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -209,7 +209,26 @@ impl TTMacroExpander for F { fn expand<'cx>(&self, ecx: &'cx mut ExtCtxt, span: Span, input: TokenStream) -> Box { - (*self)(ecx, span, &input.trees().collect::>()) + struct AvoidInterpolatedIdents; + + impl Folder for AvoidInterpolatedIdents { + fn fold_tt(&mut self, tt: tokenstream::TokenTree) -> tokenstream::TokenTree { + if let tokenstream::TokenTree::Token(_, token::Interpolated(ref nt)) = tt { + if let token::NtIdent(ident) = **nt { + return tokenstream::TokenTree::Token(ident.span, token::Ident(ident.node)); + } + } + fold::noop_fold_tt(tt, self) + } + + fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { + fold::noop_fold_mac(mac, self) + } + } + + let input: Vec<_> = + input.trees().map(|tt| AvoidInterpolatedIdents.fold_tt(tt)).collect(); + (*self)(ecx, span, &input) } } diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 9ee427eed35..6cd1fea2e75 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -492,7 +492,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { _ => {} } // check at the beginning and the parser checks after each bump - p.check_unknown_macro_variable(); + p.process_potential_macro_variable(); match name { "item" => match panictry!(p.parse_item()) { Some(i) => token::NtItem(i), diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 66f5520b882..93348c8f083 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -121,7 +121,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, p.root_module_name = cx.current_expansion.module.mod_path.last() .map(|id| id.name.as_str().to_string()); - p.check_unknown_macro_variable(); + p.process_potential_macro_variable(); // Let the context choose how to interpret the result. // Weird, but useful for X-macros. return Box::new(ParserAnyMacro { diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index 12e746e024d..d216effbd45 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -136,11 +136,14 @@ pub fn parse(input: tokenstream::TokenStream, expect_matchers: bool, sess: &Pars TokenTree::Token(start_sp, token::SubstNt(ident)) if expect_matchers => { let span = match trees.next() { Some(tokenstream::TokenTree::Token(span, token::Colon)) => match trees.next() { - Some(tokenstream::TokenTree::Token(end_sp, token::Ident(kind))) => { - let span = Span { lo: start_sp.lo, ..end_sp }; - result.push(TokenTree::MetaVarDecl(span, ident, kind)); - continue - } + Some(tokenstream::TokenTree::Token(end_sp, ref tok)) => match tok.ident() { + Some(kind) => { + let span = Span { lo: start_sp.lo, ..end_sp }; + result.push(TokenTree::MetaVarDecl(span, ident, kind)); + continue + } + _ => end_sp, + }, tree @ _ => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span), }, tree @ _ => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp), diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 24004492be2..947089b0b9a 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -12,7 +12,7 @@ use ast::Ident; use errors::Handler; use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; use ext::tt::quoted; -use parse::token::{self, SubstNt, Token, NtIdent, NtTT}; +use parse::token::{self, SubstNt, Token, NtTT}; use syntax_pos::{Span, DUMMY_SP}; use tokenstream::{TokenStream, TokenTree, Delimited}; use util::small_vector::SmallVector; @@ -154,13 +154,6 @@ pub fn transcribe(sp_diag: &Handler, None => result.push(TokenTree::Token(sp, SubstNt(ident)).into()), Some(cur_matched) => if let MatchedNonterminal(ref nt) = *cur_matched { match **nt { - // sidestep the interpolation tricks for ident because - // (a) idents can be in lots of places, so it'd be a pain - // (b) we actually can, since it's a token. - NtIdent(ref sn) => { - let token = TokenTree::Token(sn.span, token::Ident(sn.node)); - result.push(token.into()); - } NtTT(ref tt) => result.push(tt.clone().into()), _ => { let token = TokenTree::Token(sp, token::Interpolated(nt.clone())); diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index b5d0a46de49..c63a6524f74 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -218,9 +218,7 @@ pub fn filemap_to_stream(sess: &ParseSess, filemap: Rc) -> TokenStream /// Given stream and the ParseSess, produce a parser pub fn stream_to_parser<'a>(sess: &'a ParseSess, stream: TokenStream) -> Parser<'a> { - let mut p = Parser::new(sess, stream, None, false); - p.check_unknown_macro_variable(); - p + Parser::new(sess, stream, None, false) } /// Parse a string representing a character literal into its final form. diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b0611d75290..db2878c6b1e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -160,6 +160,7 @@ pub struct Parser<'a> { /// the span of the current token: pub span: Span, /// the span of the previous token: + pub meta_var_span: Option, pub prev_span: Span, /// the previous token kind prev_token_kind: PrevTokenKind, @@ -417,6 +418,7 @@ impl<'a> Parser<'a> { token: token::Underscore, span: syntax_pos::DUMMY_SP, prev_span: syntax_pos::DUMMY_SP, + meta_var_span: None, prev_token_kind: PrevTokenKind::Other, restrictions: Restrictions::empty(), obsolete_set: HashSet::new(), @@ -443,6 +445,7 @@ impl<'a> Parser<'a> { parser.directory.path = PathBuf::from(sess.codemap().span_to_filename(parser.span)); parser.directory.path.pop(); } + parser.process_potential_macro_variable(); parser } @@ -1012,7 +1015,7 @@ impl<'a> Parser<'a> { self.bug("attempted to bump the parser past EOF (may be stuck in a loop)"); } - self.prev_span = self.span; + self.prev_span = self.meta_var_span.take().unwrap_or(self.span); // Record last token kind for possible error recovery. self.prev_token_kind = match self.token { @@ -1028,7 +1031,7 @@ impl<'a> Parser<'a> { self.token = next.tok; self.expected_tokens.clear(); // check after each token - self.check_unknown_macro_variable(); + self.process_potential_macro_variable(); } /// Advance the parser using provided token as a next one. Use this when @@ -1722,7 +1725,7 @@ impl<'a> Parser<'a> { pub fn parse_path(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> { maybe_whole!(self, NtPath, |x| x); - let lo = self.span; + let lo = self.meta_var_span.unwrap_or(self.span); let is_global = self.eat(&token::ModSep); // Parse any number of segments and bound sets. A segment is an @@ -1744,13 +1747,9 @@ impl<'a> Parser<'a> { segments.insert(0, PathSegment::crate_root()); } - // Assemble the span. - // FIXME(#39450) This is bogus if part of the path is macro generated. - let span = lo.to(self.prev_span); - // Assemble the result. Ok(ast::Path { - span: span, + span: lo.to(self.prev_span), segments: segments, }) } @@ -1763,8 +1762,8 @@ impl<'a> Parser<'a> { let mut segments = Vec::new(); loop { // First, parse an identifier. + let ident_span = self.span; let identifier = self.parse_path_segment_ident()?; - let ident_span = self.prev_span; if self.check(&token::ModSep) && self.look_ahead(1, |t| *t == token::Lt) { self.bump(); @@ -1831,8 +1830,8 @@ impl<'a> Parser<'a> { let mut segments = Vec::new(); loop { // First, parse an identifier. + let ident_span = self.span; let identifier = self.parse_path_segment_ident()?; - let ident_span = self.prev_span; // If we do not see a `::`, stop. if !self.eat(&token::ModSep) { @@ -1873,10 +1872,11 @@ impl<'a> Parser<'a> { let mut segments = Vec::new(); loop { // First, parse an identifier. + let ident_span = self.span; let identifier = self.parse_path_segment_ident()?; // Assemble and push the result. - segments.push(PathSegment::from_ident(identifier, self.prev_span)); + segments.push(PathSegment::from_ident(identifier, ident_span)); // If we do not see a `::` or see `::{`/`::*`, stop. if !self.check(&token::ModSep) || self.is_import_coupler() { @@ -1896,8 +1896,9 @@ impl<'a> Parser<'a> { fn expect_lifetime(&mut self) -> Lifetime { match self.token { token::Lifetime(ident) => { + let ident_span = self.span; self.bump(); - Lifetime { name: ident.name, span: self.prev_span, id: ast::DUMMY_NODE_ID } + Lifetime { name: ident.name, span: ident_span, id: ast::DUMMY_NODE_ID } } _ => self.span_bug(self.span, "not a lifetime") } @@ -2568,10 +2569,23 @@ impl<'a> Parser<'a> { return Ok(e); } - pub fn check_unknown_macro_variable(&mut self) { - if let token::SubstNt(name) = self.token { - self.fatal(&format!("unknown macro variable `{}`", name)).emit() - } + pub fn process_potential_macro_variable(&mut self) { + let ident = match self.token { + token::SubstNt(name) => { + self.fatal(&format!("unknown macro variable `{}`", name)).emit(); + return + } + token::Interpolated(ref nt) => { + self.meta_var_span = Some(self.span); + match **nt { + token::NtIdent(ident) => ident, + _ => return, + } + } + _ => return, + }; + self.token = token::Ident(ident.node); + self.span = ident.span; } /// parse a single token tree from the input. @@ -2589,9 +2603,9 @@ impl<'a> Parser<'a> { }, token::CloseDelim(_) | token::Eof => unreachable!(), _ => { - let token = mem::replace(&mut self.token, token::Underscore); + let (token, span) = (mem::replace(&mut self.token, token::Underscore), self.span); self.bump(); - TokenTree::Token(self.prev_span, token) + TokenTree::Token(span, token) } } } @@ -3489,9 +3503,9 @@ impl<'a> Parser<'a> { fn parse_pat_ident(&mut self, binding_mode: ast::BindingMode) -> PResult<'a, PatKind> { + let ident_span = self.span; let ident = self.parse_ident()?; - let prev_span = self.prev_span; - let name = codemap::Spanned{span: prev_span, node: ident}; + let name = codemap::Spanned{span: ident_span, node: ident}; let sub = if self.eat(&token::At) { Some(self.parse_pat()?) } else { @@ -4364,7 +4378,7 @@ impl<'a> Parser<'a> { fn parse_self_arg(&mut self) -> PResult<'a, Option> { let expect_ident = |this: &mut Self| match this.token { // Preserve hygienic context. - token::Ident(ident) => { this.bump(); codemap::respan(this.prev_span, ident) } + token::Ident(ident) => { let sp = this.span; this.bump(); codemap::respan(sp, ident) } _ => unreachable!() }; let isolated_self = |this: &mut Self, n| { diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 519d5bd98e4..74aa3984a9a 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -211,9 +211,7 @@ impl Token { ModSep => true, // global path Pound => true, // expression attributes Interpolated(ref nt) => match **nt { - NtExpr(..) => true, - NtBlock(..) => true, - NtPath(..) => true, + NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) => true, _ => false, }, _ => false, @@ -236,8 +234,7 @@ impl Token { Lt | BinOp(Shl) => true, // associated path ModSep => true, // global path Interpolated(ref nt) => match **nt { - NtTy(..) => true, - NtPath(..) => true, + NtIdent(..) | NtTy(..) | NtPath(..) => true, _ => false, }, _ => false, @@ -252,14 +249,22 @@ impl Token { } } - /// Returns `true` if the token is an identifier. - pub fn is_ident(&self) -> bool { + pub fn ident(&self) -> Option { match *self { - Ident(..) => true, - _ => false, + Ident(ident) => Some(ident), + Interpolated(ref nt) => match **nt { + NtIdent(ident) => Some(ident.node), + _ => None, + }, + _ => None, } } + /// Returns `true` if the token is an identifier. + pub fn is_ident(&self) -> bool { + self.ident().is_some() + } + /// Returns `true` if the token is a documentation comment. pub fn is_doc_comment(&self) -> bool { match *self { @@ -311,18 +316,15 @@ impl Token { /// Returns `true` if the token is a given keyword, `kw`. pub fn is_keyword(&self, kw: keywords::Keyword) -> bool { - match *self { - Ident(id) => id.name == kw.name(), - _ => false, - } + self.ident().map(|ident| ident.name == kw.name()).unwrap_or(false) } pub fn is_path_segment_keyword(&self) -> bool { - match *self { - Ident(id) => id.name == keywords::Super.name() || - id.name == keywords::SelfValue.name() || - id.name == keywords::SelfType.name(), - _ => false, + match self.ident() { + Some(id) => id.name == keywords::Super.name() || + id.name == keywords::SelfValue.name() || + id.name == keywords::SelfType.name(), + None => false, } } @@ -333,18 +335,16 @@ impl Token { /// Returns `true` if the token is a strict keyword. pub fn is_strict_keyword(&self) -> bool { - match *self { - Ident(id) => id.name >= keywords::As.name() && - id.name <= keywords::While.name(), + match self.ident() { + Some(id) => id.name >= keywords::As.name() && id.name <= keywords::While.name(), _ => false, } } /// Returns `true` if the token is a keyword reserved for possible future use. pub fn is_reserved_keyword(&self) -> bool { - match *self { - Ident(id) => id.name >= keywords::Abstract.name() && - id.name <= keywords::Yield.name(), + match self.ident() { + Some(id) => id.name >= keywords::Abstract.name() && id.name <= keywords::Yield.name(), _ => false, } } -- cgit 1.4.1-3-g733a5 From b3763862280946cab09cbedc4ad5626ebd95a5b2 Mon Sep 17 00:00:00 2001 From: Thomas Jespersen Date: Fri, 17 Mar 2017 23:11:27 +0100 Subject: Replace hardcoded forward slash with path::MAIN_SEPARATOR Fixes #40149 --- src/libstd/sys_common/backtrace.rs | 4 +-- src/libsyntax/parse/parser.rs | 9 ++++--- src/test/parse-fail/mod_file_not_exist.rs | 2 ++ src/test/parse-fail/mod_file_not_exist_windows.rs | 32 +++++++++++++++++++++++ 4 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 src/test/parse-fail/mod_file_not_exist_windows.rs (limited to 'src/libsyntax/parse') diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 99297b781e4..f5c188f7a75 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -19,7 +19,7 @@ use io; use libc; use str; use sync::atomic::{self, Ordering}; -use path::Path; +use path::{self, Path}; use sys::mutex::Mutex; use ptr; @@ -262,7 +262,7 @@ fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int, if let Ok(cwd) = env::current_dir() { if let Ok(stripped) = file_path.strip_prefix(&cwd) { if let Some(s) = stripped.to_str() { - write!(w, " at ./{}:{}", s, line)?; + write!(w, " at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?; already_printed = true; } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index db2878c6b1e..c2c3e5a6855 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -59,7 +59,7 @@ use util::ThinVec; use std::collections::HashSet; use std::{cmp, mem, slice}; -use std::path::{Path, PathBuf}; +use std::path::{self, Path, PathBuf}; bitflags! { flags Restrictions: u8 { @@ -5146,7 +5146,7 @@ impl<'a> Parser<'a> { pub fn default_submod_path(id: ast::Ident, dir_path: &Path, codemap: &CodeMap) -> ModulePath { let mod_name = id.to_string(); let default_path_str = format!("{}.rs", mod_name); - let secondary_path_str = format!("{}/mod.rs", mod_name); + let secondary_path_str = format!("{}{}mod.rs", mod_name, path::MAIN_SEPARATOR); let default_path = dir_path.join(&default_path_str); let secondary_path = dir_path.join(&secondary_path_str); let default_exists = codemap.file_exists(&default_path); @@ -5224,8 +5224,9 @@ impl<'a> Parser<'a> { }; err.span_note(id_sp, &format!("maybe move this module `{0}` to its own directory \ - via `{0}/mod.rs`", - this_module)); + via `{0}{1}mod.rs`", + this_module, + path::MAIN_SEPARATOR)); if paths.path_exists { err.span_note(id_sp, &format!("... or maybe `use` the module `{}` instead \ diff --git a/src/test/parse-fail/mod_file_not_exist.rs b/src/test/parse-fail/mod_file_not_exist.rs index 7736394a6f5..4bc6e706d42 100644 --- a/src/test/parse-fail/mod_file_not_exist.rs +++ b/src/test/parse-fail/mod_file_not_exist.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-windows + // compile-flags: -Z parse-only mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` diff --git a/src/test/parse-fail/mod_file_not_exist_windows.rs b/src/test/parse-fail/mod_file_not_exist_windows.rs new file mode 100644 index 00000000000..c58603b4398 --- /dev/null +++ b/src/test/parse-fail/mod_file_not_exist_windows.rs @@ -0,0 +1,32 @@ +// 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. + +// ignore-gnu +// ignore-android +// ignore-bitrig +// ignore-macos +// ignore-dragonfly +// ignore-freebsd +// ignore-haiku +// ignore-ios +// ignore-linux +// ignore-netbsd +// ignore-openbsd +// ignore-solaris +// ignore-emscripten + +// compile-flags: -Z parse-only + +mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` +//~^ HELP name the file either not_a_real_file.rs or not_a_real_file\mod.rs inside the directory + +fn main() { + assert_eq!(mod_file_aux::bar(), 10); +} -- cgit 1.4.1-3-g733a5 From 56847af9163284f928d5632a3d0d29399716414f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 17 Mar 2017 09:51:31 -0400 Subject: port the match code to use `CoerceMany` `match { }` now (correctly?) indicates divergence, which results in more unreachable warnings. We also avoid fallback to `!` if there is just one arm (see new test: `match-unresolved-one-arm.rs`). --- src/librustc_typeck/check/_match.rs | 90 ++++++++++------------ src/libsyntax/parse/obsolete.rs | 1 + .../match-no-arms-unreachable-after.rs | 22 ++++++ ...h-unreachable-warning-with-diverging-discrim.rs | 16 ++++ src/test/compile-fail/match-unresolved-one-arm.rs | 17 ++++ 5 files changed, 95 insertions(+), 51 deletions(-) create mode 100644 src/test/compile-fail/match-no-arms-unreachable-after.rs create mode 100644 src/test/compile-fail/match-unreachable-warning-with-diverging-discrim.rs create mode 100644 src/test/compile-fail/match-unresolved-one-arm.rs (limited to 'src/libsyntax/parse') diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index feed5752cf8..f0d2598a0fb 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -16,6 +16,7 @@ use rustc::infer::type_variable::TypeVariableOrigin; use rustc::traits::ObligationCauseCode; use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; use check::{FnCtxt, Expectation, Diverges}; +use check::coercion::CoerceMany; use util::nodemap::FxHashMap; use std::collections::hash_map::Entry::{Occupied, Vacant}; @@ -414,6 +415,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span)); self.check_expr_has_type(discrim, discrim_ty); }; + + // If the discriminant diverges, the match is pointless (e.g., + // `match (return) { }`). + self.warn_if_unreachable(expr.id, expr.span, "expression"); + + // If there are no arms, that is a diverging match; a special case. + if arms.is_empty() { + self.diverges.set(self.diverges.get() | Diverges::Always); + return tcx.types.never; + } + + // Otherwise, we have to union together the types that the + // arms produce and so forth. + let discrim_diverges = self.diverges.get(); self.diverges.set(Diverges::Maybe); @@ -426,6 +441,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_pat(&p, discrim_ty); all_pats_diverge &= self.diverges.get(); } + // As discussed with @eddyb, this is for disabling unreachable_code // warnings on patterns (they're now subsumed by unreachable_patterns // warnings). @@ -444,20 +460,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // on any empty type and is therefore unreachable; should the flow // of execution reach it, we will panic, so bottom is an appropriate // type in that case) - let expected = expected.adjust_for_branches(self); - let mut result_ty = self.next_diverging_ty_var( - TypeVariableOrigin::DivergingBlockExpr(expr.span)); let mut all_arms_diverge = Diverges::WarnedAlways; - let coerce_first = match expected { - // We don't coerce to `()` so that if the match expression is a - // statement it's branches can have any consistent type. That allows - // us to give better error messages (pointing to a usually better - // arm for inconsistent arms or to the whole match when a `()` type - // is required). - Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => { - ety - } - _ => result_ty + + let expected = expected.adjust_for_branches(self); + + let mut coercion = { + let coerce_first = match expected { + // We don't coerce to `()` so that if the match expression is a + // statement it's branches can have any consistent type. That allows + // us to give better error messages (pointing to a usually better + // arm for inconsistent arms or to the whole match when a `()` type + // is required). + Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => ety, + _ => self.next_ty_var(TypeVariableOrigin::MiscVariable(expr.span)), + }; + CoerceMany::new(coerce_first) }; for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() { @@ -470,11 +487,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let arm_ty = self.check_expr_with_expectation(&arm.body, expected); all_arms_diverge &= self.diverges.get(); - if result_ty.references_error() || arm_ty.references_error() { - result_ty = tcx.types.err; - continue; - } - // Handle the fallback arm of a desugared if-let like a missing else. let is_if_let_fallback = match match_src { hir::MatchSource::IfLetDesugar { contains_else_clause: false } => { @@ -483,47 +495,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => false }; - let cause = if is_if_let_fallback { - self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse) + if is_if_let_fallback { + let cause = self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse); + assert!(arm_ty.is_nil()); + coercion.coerce_forced_unit(self, &cause); } else { - self.cause(expr.span, ObligationCauseCode::MatchExpressionArm { + let cause = self.cause(expr.span, ObligationCauseCode::MatchExpressionArm { arm_span: arm.body.span, source: match_src - }) - }; - - let result = if is_if_let_fallback { - self.eq_types(true, &cause, arm_ty, result_ty) - .map(|infer_ok| { - self.register_infer_ok_obligations(infer_ok); - arm_ty - }) - } else if i == 0 { - // Special-case the first arm, as it has no "previous expressions". - self.try_coerce(&arm.body, arm_ty, coerce_first) - } else { - let prev_arms = || arms[..i].iter().map(|arm| &*arm.body); - self.try_find_coercion_lub(&cause, prev_arms, result_ty, &arm.body, arm_ty) - }; - - result_ty = match result { - Ok(ty) => ty, - Err(e) => { - let (expected, found) = if is_if_let_fallback { - (arm_ty, result_ty) - } else { - (result_ty, arm_ty) - }; - self.report_mismatched_types(&cause, expected, found, e).emit(); - self.tcx.types.err - } - }; + }); + coercion.coerce(self, &cause, &arm.body, arm_ty); + } } // We won't diverge unless the discriminant or all arms diverge. self.diverges.set(discrim_diverges | all_arms_diverge); - result_ty + coercion.complete(self) } fn check_pat_struct(&self, diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index a46a788ca08..d5baec675e4 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -36,6 +36,7 @@ pub trait ParserObsoleteMethods { impl<'a> ParserObsoleteMethods for parser::Parser<'a> { /// Reports an obsolete syntax non-fatal error. #[allow(unused_variables)] + #[allow(unreachable_code)] fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax) { let (kind_str, desc, error) = match kind { // Nothing here at the moment diff --git a/src/test/compile-fail/match-no-arms-unreachable-after.rs b/src/test/compile-fail/match-no-arms-unreachable-after.rs new file mode 100644 index 00000000000..db08f5e5e66 --- /dev/null +++ b/src/test/compile-fail/match-no-arms-unreachable-after.rs @@ -0,0 +1,22 @@ +// 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. + +#![allow(warnings)] +#![deny(unreachable_code)] + +enum Void { } + +fn foo(v: Void) { + match v { } + let x = 2; //~ ERROR unreachable +} + +fn main() { +} diff --git a/src/test/compile-fail/match-unreachable-warning-with-diverging-discrim.rs b/src/test/compile-fail/match-unreachable-warning-with-diverging-discrim.rs new file mode 100644 index 00000000000..aae0f3135d8 --- /dev/null +++ b/src/test/compile-fail/match-unreachable-warning-with-diverging-discrim.rs @@ -0,0 +1,16 @@ +// 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. + +#![allow(unused_parens)] +#![deny(unreachable_code)] + +fn main() { + match (return) { } //~ ERROR unreachable expression +} diff --git a/src/test/compile-fail/match-unresolved-one-arm.rs b/src/test/compile-fail/match-unresolved-one-arm.rs new file mode 100644 index 00000000000..ea0f8db99e8 --- /dev/null +++ b/src/test/compile-fail/match-unresolved-one-arm.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. + +fn foo() -> T { panic!("Rocks for my pillow") } + +fn main() { + let x = match () { //~ ERROR type annotations needed + () => foo() // T here should be unresolved + }; +} -- cgit 1.4.1-3-g733a5 From b83352e44c36e81db7f00eb60e78ff3828c51c9e Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Tue, 28 Mar 2017 18:56:29 -0700 Subject: Introduce `TyErr` independent from `TyInfer` Add a `TyErr` type to represent unknown types in places where parse errors have happened, while still able to build the AST. Initially only used to represent incorrectly written fn arguments and avoid "expected X parameters, found Y" errors when called with the appropriate amount of parameters. We cannot use `TyInfer` for this as `_` is not allowed as a valid argument type. Example output: ```rust error: expected one of `:` or `@`, found `,` --> file.rs:12:9 | 12 | fn bar(x, y: usize) {} | ^ error[E0061]: this function takes 2 parameters but 3 parameters were supplied --> file.rs:19:9 | 12 | fn bar(x, y) {} | --------------- defined here ... 19 | bar(1, 2, 3); | ^^^^^^^ expected 2 parameters ``` --- src/librustc/hir/intravisit.rs | 2 +- src/librustc/hir/lowering.rs | 1 + src/librustc/hir/mod.rs | 2 + src/librustc/hir/print.rs | 3 ++ .../calculate_svh/svh_visitor.rs | 6 ++- src/librustc_typeck/astconv.rs | 3 ++ src/librustdoc/clean/mod.rs | 2 +- src/libsyntax/ast.rs | 2 + src/libsyntax/fold.rs | 2 +- src/libsyntax/parse/parser.rs | 25 ++++++++++- src/libsyntax/print/pprust.rs | 3 ++ src/libsyntax/visit.rs | 2 +- src/test/ui/span/issue-34264.rs | 20 +++++++++ src/test/ui/span/issue-34264.stderr | 49 ++++++++++++++++++++++ 14 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/span/issue-34264.rs create mode 100644 src/test/ui/span/issue-34264.stderr (limited to 'src/libsyntax/parse') diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index c7ad143c949..2c8b145f126 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -578,7 +578,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { TyTypeof(expression) => { visitor.visit_nested_body(expression) } - TyInfer => {} + TyInfer | TyErr => {} } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 17185a6ab69..acc6d21ddc6 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -555,6 +555,7 @@ impl<'a> LoweringContext<'a> { fn lower_ty(&mut self, t: &Ty) -> P { let kind = match t.node { TyKind::Infer => hir::TyInfer, + TyKind::Err => hir::TyErr, TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)), TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)), TyKind::Rptr(ref region, ref mt) => { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index d5000ac9c18..0da405d1821 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1351,6 +1351,8 @@ pub enum Ty_ { /// TyInfer means the type should be inferred instead of it having been /// specified. This can appear anywhere in a type. TyInfer, + /// Placeholder for a type that has failed to be defined. + TyErr, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 04a65fd5e3a..4a5a35aa82c 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -450,6 +450,9 @@ impl<'a> State<'a> { hir::TyInfer => { word(&mut self.s, "_")?; } + hir::TyErr => { + word(&mut self.s, "?")?; + } } self.end() } diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 5401b371888..4700b77be07 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -432,7 +432,8 @@ enum SawTyComponent { SawTyObjectSum, SawTyImplTrait, SawTyTypeof, - SawTyInfer + SawTyInfer, + SawTyErr, } fn saw_ty(node: &Ty_) -> SawTyComponent { @@ -448,7 +449,8 @@ fn saw_ty(node: &Ty_) -> SawTyComponent { TyTraitObject(..) => SawTyObjectSum, TyImplTrait(..) => SawTyImplTrait, TyTypeof(..) => SawTyTypeof, - TyInfer => SawTyInfer + TyInfer => SawTyInfer, + TyErr => SawTyErr, } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 923ec05c22b..66c4a81a5c0 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1229,6 +1229,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // handled specially and will not descend into this routine. self.ty_infer(ast_ty.span) } + hir::TyErr => { + tcx.types.err + } }; cache.borrow_mut().insert(ast_ty.id, result_ty); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f3ea6c4467c..ac72d7d29a2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1805,7 +1805,7 @@ impl Clean for hir::Ty { } TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)), TyImplTrait(ref bounds) => ImplTrait(bounds.clean(cx)), - TyInfer => Infer, + TyInfer | TyErr => Infer, TyTypeof(..) => panic!("Unimplemented type {:?}", self.node), } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9eb86aa006d..c6a3e8a2ded 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1361,6 +1361,8 @@ pub enum TyKind { ImplicitSelf, // A macro in the type position. Mac(Mac), + /// Placeholder for a kind that has failed to be defined. + Err, } /// Inline assembly dialect. diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 1a4e196ac55..92e25b00e0a 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -358,7 +358,7 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { t.map(|Ty {id, node, span}| Ty { id: fld.new_id(id), node: match node { - TyKind::Infer | TyKind::ImplicitSelf => node, + TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => node, TyKind::Slice(ty) => TyKind::Slice(fld.fold_ty(ty)), TyKind::Ptr(mt) => TyKind::Ptr(fld.fold_mt(mt)), TyKind::Rptr(region, mt) => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c2c3e5a6855..23fc1351426 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -407,6 +407,25 @@ impl From> for LhsExpr { } } +/// Create a placeholder argument. +fn dummy_arg(span: Span) -> Arg { + let spanned = Spanned { + span: span, + node: keywords::Invalid.ident() + }; + let pat = P(Pat { + id: ast::DUMMY_NODE_ID, + node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), spanned, None), + span: span + }); + let ty = Ty { + node: TyKind::Err, + span: span, + id: ast::DUMMY_NODE_ID + }; + Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID } +} + impl<'a> Parser<'a> { pub fn new(sess: &'a ParseSess, tokens: TokenStream, @@ -4343,8 +4362,12 @@ impl<'a> Parser<'a> { Ok(arg) => Ok(Some(arg)), Err(mut e) => { e.emit(); + let lo = p.prev_span; + // Skip every token until next possible arg or end. p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]); - Ok(None) + // Create a placeholder argument for proper arg count (#34264). + let span = lo.to(p.prev_span); + Ok(Some(dummy_arg(span))) } } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f042a18d610..e7feff2b79f 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1095,6 +1095,9 @@ impl<'a> State<'a> { ast::TyKind::Infer => { word(&mut self.s, "_")?; } + ast::TyKind::Err => { + word(&mut self.s, "?")?; + } ast::TyKind::ImplicitSelf => { word(&mut self.s, "Self")?; } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index a5333f3bb6a..b5e9a1892ac 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -350,7 +350,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { TyKind::Typeof(ref expression) => { visitor.visit_expr(expression) } - TyKind::Infer | TyKind::ImplicitSelf => {} + TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {} TyKind::Mac(ref mac) => { visitor.visit_mac(mac) } diff --git a/src/test/ui/span/issue-34264.rs b/src/test/ui/span/issue-34264.rs new file mode 100644 index 00000000000..00482f50618 --- /dev/null +++ b/src/test/ui/span/issue-34264.rs @@ -0,0 +1,20 @@ +// Copyright 2017 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. + +fn foo(Option, String) {} +fn bar(x, y: usize) {} + +fn main() { + foo(Some(42), 2); + foo(Some(42), 2, ""); + bar("", ""); + bar(1, 2); + bar(1, 2, 3); +} diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr new file mode 100644 index 00000000000..c79db54eaef --- /dev/null +++ b/src/test/ui/span/issue-34264.stderr @@ -0,0 +1,49 @@ +error: expected one of `:` or `@`, found `<` + --> $DIR/issue-34264.rs:11:14 + | +11 | fn foo(Option, String) {} + | ^ + +error: expected one of `:` or `@`, found `)` + --> $DIR/issue-34264.rs:11:27 + | +11 | fn foo(Option, String) {} + | ^ + +error: expected one of `:` or `@`, found `,` + --> $DIR/issue-34264.rs:12:9 + | +12 | fn bar(x, y: usize) {} + | ^ + +error[E0061]: this function takes 2 parameters but 3 parameters were supplied + --> $DIR/issue-34264.rs:16:9 + | +11 | fn foo(Option, String) {} + | ------------------------------ defined here +... +16 | foo(Some(42), 2, ""); + | ^^^^^^^^^^^^^^^ expected 2 parameters + +error[E0308]: mismatched types + --> $DIR/issue-34264.rs:17:13 + | +17 | bar("", ""); + | ^^ expected usize, found reference + | + = note: expected type `usize` + found type `&'static str` + = help: here are some functions which might fulfill your needs: + - .len() + +error[E0061]: this function takes 2 parameters but 3 parameters were supplied + --> $DIR/issue-34264.rs:19:9 + | +12 | fn bar(x, y: usize) {} + | ---------------------- defined here +... +19 | bar(1, 2, 3); + | ^^^^^^^ expected 2 parameters + +error: aborting due to 3 previous errors + -- cgit 1.4.1-3-g733a5 From 6a9448b523b95dbc850e856508342644fc17db45 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 3 Apr 2017 22:23:32 +0000 Subject: Fix bug parsing `#[derive]` macro invocations. --- src/librustc_resolve/macros.rs | 6 ++++-- src/libsyntax/ext/derive.rs | 3 ++- src/libsyntax/parse/parser.rs | 20 ++++++++++++++++++++ src/test/run-pass/issue-40962.rs | 20 ++++++++++++++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 src/test/run-pass/issue-40962.rs (limited to 'src/libsyntax/parse') diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 05f30f039c8..966cb7ee8d8 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -222,8 +222,10 @@ impl<'a> base::Resolver for Resolver<'a> { let name = unwrap_or!(attrs[i].name(), continue); if name == "derive" { - let result = attrs[i].parse_list(&self.session.parse_sess, - |parser| parser.parse_path(PathStyle::Mod)); + let result = attrs[i].parse_list(&self.session.parse_sess, |parser| { + parser.parse_path_allowing_meta(PathStyle::Mod) + }); + let mut traits = match result { Ok(traits) => traits, Err(mut e) => { diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index c79040424f6..e7c5d8278d9 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -26,7 +26,8 @@ pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec) -> Vec return true; } - match attr.parse_list(cx.parse_sess, |parser| parser.parse_path(PathStyle::Mod)) { + match attr.parse_list(cx.parse_sess, + |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) { Ok(ref traits) if traits.is_empty() => { cx.span_warn(attr.span, "empty trait list in `derive`"); false diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c2c3e5a6855..a89811d8abb 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1754,6 +1754,26 @@ impl<'a> Parser<'a> { }) } + /// Like `parse_path`, but also supports parsing `Word` meta items into paths for back-compat. + /// This is used when parsing derive macro paths in `#[derive]` attributes. + pub fn parse_path_allowing_meta(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> { + let meta_ident = match self.token { + token::Interpolated(ref nt) => match **nt { + token::NtMeta(ref meta) => match meta.node { + ast::MetaItemKind::Word => Some(ast::Ident::with_empty_ctxt(meta.name)), + _ => None, + }, + _ => None, + }, + _ => None, + }; + if let Some(ident) = meta_ident { + self.bump(); + return Ok(ast::Path::from_ident(self.prev_span, ident)); + } + self.parse_path(mode) + } + /// Examples: /// - `a::b::c` /// - `a::b::c(V) -> W` diff --git a/src/test/run-pass/issue-40962.rs b/src/test/run-pass/issue-40962.rs new file mode 100644 index 00000000000..b35cfa12eab --- /dev/null +++ b/src/test/run-pass/issue-40962.rs @@ -0,0 +1,20 @@ +// Copyright 2017 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. + +macro_rules! m { + ($i:meta) => { + #[derive($i)] + struct S; + } +} + +m!(Clone); + +fn main() {} -- cgit 1.4.1-3-g733a5 From 44e414c4770ff0800c375ddbb8e0f46ee00bcab1 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Wed, 5 Apr 2017 09:50:04 -0700 Subject: Use proper span for tuple index parsed as float Fix diagnostic suggestion from: ```rust help: try parenthesizing the first index | (1, (2, 3)).((1, (2, 3)).1).1; ``` to the correct: ```rust help: try parenthesizing the first index | ((1, (2, 3)).1).1; ``` --- src/libsyntax/parse/parser.rs | 6 +++--- src/test/parse-fail/tuple-float-index.rs | 17 ----------------- src/test/ui/suggestions/tuple-float-index.rs | 15 +++++++++++++++ src/test/ui/suggestions/tuple-float-index.stderr | 11 +++++++++++ 4 files changed, 29 insertions(+), 20 deletions(-) delete mode 100644 src/test/parse-fail/tuple-float-index.rs create mode 100644 src/test/ui/suggestions/tuple-float-index.rs create mode 100644 src/test/ui/suggestions/tuple-float-index.stderr (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c2c3e5a6855..0d2c9b92ed7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2498,10 +2498,10 @@ impl<'a> Parser<'a> { } token::Literal(token::Float(n), _suf) => { self.bump(); - let prev_span = self.prev_span; let fstr = n.as_str(); - let mut err = self.diagnostic().struct_span_err(prev_span, + let mut err = self.diagnostic().struct_span_err(self.prev_span, &format!("unexpected token: `{}`", n)); + err.span_label(self.prev_span, &"unexpected token"); if fstr.chars().all(|x| "0123456789.".contains(x)) { let float = match fstr.parse::().ok() { Some(f) => f, @@ -2519,7 +2519,7 @@ impl<'a> Parser<'a> { word(&mut s.s, fstr.splitn(2, ".").last().unwrap()) }); err.span_suggestion( - prev_span, + lo.to(self.prev_span), "try parenthesizing the first index", sugg); } diff --git a/src/test/parse-fail/tuple-float-index.rs b/src/test/parse-fail/tuple-float-index.rs deleted file mode 100644 index 57ad89ad374..00000000000 --- a/src/test/parse-fail/tuple-float-index.rs +++ /dev/null @@ -1,17 +0,0 @@ -// 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 - -fn main () { - (1, (2, 3)).1.1; //~ ERROR unexpected token - //~^ HELP try parenthesizing the first index - //~| SUGGESTION ((1, (2, 3)).1).1 -} diff --git a/src/test/ui/suggestions/tuple-float-index.rs b/src/test/ui/suggestions/tuple-float-index.rs new file mode 100644 index 00000000000..8bfbd0e74db --- /dev/null +++ b/src/test/ui/suggestions/tuple-float-index.rs @@ -0,0 +1,15 @@ +// 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 + +fn main () { + (1, (2, 3)).1.1; +} diff --git a/src/test/ui/suggestions/tuple-float-index.stderr b/src/test/ui/suggestions/tuple-float-index.stderr new file mode 100644 index 00000000000..abe04dc1aa2 --- /dev/null +++ b/src/test/ui/suggestions/tuple-float-index.stderr @@ -0,0 +1,11 @@ +error: unexpected token: `1.1` + --> $DIR/tuple-float-index.rs:14:17 + | +14 | (1, (2, 3)).1.1; + | ^^^ unexpected token + | +help: try parenthesizing the first index + | ((1, (2, 3)).1).1; + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 4c80170782c168e5aae848b2911c16921e5a2f58 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sun, 9 Apr 2017 16:28:31 -0700 Subject: Point at only one char on `Span::next_point` Avoid pointing at two chars so the diagnostic output doesn't display a multiline span when starting beyond a line end. --- src/libsyntax/parse/parser.rs | 6 ++++-- src/libsyntax_pos/lib.rs | 2 +- src/test/ui/token/issue-41155.rs | 13 +++++++++++++ src/test/ui/token/issue-41155.stderr | 10 ++++++++++ 4 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/token/issue-41155.rs create mode 100644 src/test/ui/token/issue-41155.stderr (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 43d21015a4f..58be43526fd 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -592,8 +592,10 @@ impl<'a> Parser<'a> { } else { label_sp }; - err.span_label(sp, &label_exp); - if !sp.source_equal(&self.span) { + if self.span.contains(sp) { + err.span_label(self.span, &label_exp); + } else { + err.span_label(sp, &label_exp); err.span_label(self.span, &"unexpected token"); } Err(err) diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 9b88b9f7696..aaafcadc38a 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -89,7 +89,7 @@ impl Span { /// Returns a new span representing the next character after the end-point of this span pub fn next_point(self) -> Span { let lo = cmp::max(self.hi.0, self.lo.0 + 1); - Span { lo: BytePos(lo), hi: BytePos(lo + 1), ..self } + Span { lo: BytePos(lo), hi: BytePos(lo), ..self } } /// Returns `self` if `self` is not the dummy span, and `other` otherwise. diff --git a/src/test/ui/token/issue-41155.rs b/src/test/ui/token/issue-41155.rs new file mode 100644 index 00000000000..0f473c9e073 --- /dev/null +++ b/src/test/ui/token/issue-41155.rs @@ -0,0 +1,13 @@ +// Copyright 2017 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. + +impl S { + pub +} diff --git a/src/test/ui/token/issue-41155.stderr b/src/test/ui/token/issue-41155.stderr new file mode 100644 index 00000000000..0da3abd4eaf --- /dev/null +++ b/src/test/ui/token/issue-41155.stderr @@ -0,0 +1,10 @@ +error: expected one of `(`, `const`, `default`, `extern`, `fn`, `type`, or `unsafe`, found `}` + --> $DIR/issue-41155.rs:13:1 + | +12 | pub + | - expected one of 7 possible tokens here +13 | } + | ^ unexpected token + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From a50737051abdc943f96c6e89a732fd00e58248e8 Mon Sep 17 00:00:00 2001 From: alexey zabelin Date: Wed, 12 Apr 2017 20:46:44 -0400 Subject: Fix old docs #41158 --- src/doc/grammar.md | 8 ++++++++ src/libsyntax/parse/parser.rs | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/doc/grammar.md b/src/doc/grammar.md index 8e803aff4d6..239afd41f02 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -780,6 +780,14 @@ never_type : "!" ; **FIXME:** grammar? +### Type parameter bounds + +```antlr +bound := ty_bound | lt_bound +lt_bound := lifetime +ty_bound := [?] [ for ] simple_path +``` + ### Self types **FIXME:** grammar? diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 3b928ea93c7..5cacb0da9e5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4066,7 +4066,7 @@ impl<'a> Parser<'a> { }).emit(); } - // Parse bounds of a type parameter `BOUND + BOUND + BOUND` without trailing `+`. + // Parse bounds of a type parameter `BOUND + BOUND + BOUND`. // BOUND = TY_BOUND | LT_BOUND // LT_BOUND = LIFETIME (e.g. `'a`) // TY_BOUND = [?] [for] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) @@ -4107,7 +4107,7 @@ impl<'a> Parser<'a> { self.parse_ty_param_bounds_common(true) } - // Parse bounds of a type parameter `BOUND + BOUND + BOUND` without trailing `+`. + // Parse bounds of a type parameter `BOUND + BOUND + BOUND`. // BOUND = LT_BOUND (e.g. `'a`) fn parse_lt_param_bounds(&mut self) -> Vec { let mut lifetimes = Vec::new(); -- cgit 1.4.1-3-g733a5 From 14eac29753efd5a5e8ded83a2c8ae8e44e914320 Mon Sep 17 00:00:00 2001 From: alexey zabelin Date: Thu, 13 Apr 2017 09:53:22 -0400 Subject: Address the PR review --- src/doc/grammar.md | 3 +-- src/libsyntax/parse/parser.rs | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/doc/grammar.md b/src/doc/grammar.md index 239afd41f02..3fbf9f06d99 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -761,8 +761,6 @@ closure_type := [ 'unsafe' ] [ '<' lifetime-list '>' ] '|' arg-list '|' [ ':' bound-list ] [ '->' type ] lifetime-list := lifetime | lifetime ',' lifetime-list arg-list := ident ':' type | ident ':' type ',' arg-list -bound-list := bound | bound '+' bound-list -bound := path | lifetime ``` ### Never type @@ -786,6 +784,7 @@ never_type : "!" ; bound := ty_bound | lt_bound lt_bound := lifetime ty_bound := [?] [ for ] simple_path +bound-list := bound | bound '+' bound-list '+' ? ``` ### Self types diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5cacb0da9e5..0fddbca72cd 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4066,7 +4066,7 @@ impl<'a> Parser<'a> { }).emit(); } - // Parse bounds of a type parameter `BOUND + BOUND + BOUND`. + // Parse bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. // BOUND = TY_BOUND | LT_BOUND // LT_BOUND = LIFETIME (e.g. `'a`) // TY_BOUND = [?] [for] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) @@ -4107,7 +4107,7 @@ impl<'a> Parser<'a> { self.parse_ty_param_bounds_common(true) } - // Parse bounds of a type parameter `BOUND + BOUND + BOUND`. + // Parse bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. // BOUND = LT_BOUND (e.g. `'a`) fn parse_lt_param_bounds(&mut self) -> Vec { let mut lifetimes = Vec::new(); -- cgit 1.4.1-3-g733a5 From a2489495d909c43cfbefaeb79db6a77b13908257 Mon Sep 17 00:00:00 2001 From: Daniel Keep Date: Mon, 25 Apr 2016 02:04:01 +1000 Subject: Implementation of the `vis` macro matcher. --- src/libsyntax/ext/tt/macro_parser.rs | 1 + src/libsyntax/ext/tt/macro_rules.rs | 15 ++++- src/libsyntax/fold.rs | 1 + src/libsyntax/parse/token.rs | 2 + src/libsyntax/print/pprust.rs | 5 ++ src/test/run-pass/macro-pub-matcher.rs | 119 +++++++++++++++++++++++++++++++++ 6 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/macro-pub-matcher.rs (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 6cd1fea2e75..eb0b7c29f8d 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -529,6 +529,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { token::NtPath(panictry!(p.parse_path(PathStyle::Type))) }, "meta" => token::NtMeta(panictry!(p.parse_meta_item())), + "vis" => token::NtVis(panictry!(p.parse_visibility(true))), // this is not supposed to happen, since it has been checked // when compiling the macro. _ => p.span_bug(sp, "invalid fragment specifier") diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 93348c8f083..4e197a85ebd 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -790,6 +790,19 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result { + // Explicitly disallow `priv`, on the off chance it comes back. + match *tok { + Comma => Ok(true), + ModSep => Ok(true), + MatchNt(_, ref frag, _, _) => { + let name = frag.name.as_str(); + Ok(name == "ident" || name == "ty") + }, + Ident(i, _) if i.name.as_str() != "priv" => Ok(true), + _ => Ok(false) + } + }, "" => Ok(true), // keywords::Invalid _ => Err((format!("invalid fragment specifier `{}`", frag), "valid fragment specifiers are `ident`, `block`, \ @@ -813,7 +826,7 @@ fn has_legal_fragment_specifier(tok: "ed::TokenTree) -> Result<(), String> { fn is_legal_fragment_specifier(frag: &str) -> bool { match frag { "item" | "block" | "stmt" | "expr" | "pat" | - "path" | "ty" | "ident" | "meta" | "tt" | "" => true, + "path" | "ty" | "ident" | "meta" | "tt" | "vis" | "" => true, _ => false, } } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index a6ab8e10d9f..f39399a62e8 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -636,6 +636,7 @@ pub fn noop_fold_interpolated(nt: token::Nonterminal, fld: &mut T) token::NtWhereClause(where_clause) => token::NtWhereClause(fld.fold_where_clause(where_clause)), token::NtArg(arg) => token::NtArg(fld.fold_arg(arg)), + token::NtVis(vis) => token::NtVis(fld.fold_vis(vis)), } } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 74aa3984a9a..513aa866043 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -371,6 +371,7 @@ pub enum Nonterminal { NtGenerics(ast::Generics), NtWhereClause(ast::WhereClause), NtArg(ast::Arg), + NtVis(ast::Visibility), } impl fmt::Debug for Nonterminal { @@ -392,6 +393,7 @@ impl fmt::Debug for Nonterminal { NtGenerics(..) => f.pad("NtGenerics(..)"), NtWhereClause(..) => f.pad("NtWhereClause(..)"), NtArg(..) => f.pad("NtArg(..)"), + NtVis(..) => f.pad("NtVis(..)"), } } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 433ba3d3693..2494af2c161 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -293,6 +293,7 @@ pub fn token_to_string(tok: &Token) -> String { token::NtGenerics(ref e) => generics_to_string(&e), token::NtWhereClause(ref e) => where_clause_to_string(&e), token::NtArg(ref e) => arg_to_string(&e), + token::NtVis(ref e) => vis_to_string(&e), } } } @@ -373,6 +374,10 @@ pub fn ident_to_string(id: ast::Ident) -> String { to_string(|s| s.print_ident(id)) } +pub fn vis_to_string(v: &ast::Visibility) -> String { + to_string(|s| s.print_visibility(v)) +} + pub fn fun_to_string(decl: &ast::FnDecl, unsafety: ast::Unsafety, constness: ast::Constness, diff --git a/src/test/run-pass/macro-pub-matcher.rs b/src/test/run-pass/macro-pub-matcher.rs new file mode 100644 index 00000000000..64fa0bef464 --- /dev/null +++ b/src/test/run-pass/macro-pub-matcher.rs @@ -0,0 +1,119 @@ +#![allow(dead_code, unused_imports)] +#![feature(pub_restricted)] + +/** +Ensure that `:vis` matches can be captured in existing positions, and passed +through without the need for reparse tricks. +*/ +macro_rules! vis_passthru { + ($vis:vis const $name:ident: $ty:ty = $e:expr;) => { $vis const $name: $ty = $e; }; + ($vis:vis enum $name:ident {}) => { $vis struct $name {} }; + ($vis:vis extern "C" fn $name:ident() {}) => { $vis extern "C" fn $name() {} }; + ($vis:vis fn $name:ident() {}) => { $vis fn $name() {} }; + ($vis:vis mod $name:ident {}) => { $vis mod $name {} }; + ($vis:vis static $name:ident: $ty:ty = $e:expr;) => { $vis static $name: $ty = $e; }; + ($vis:vis struct $name:ident;) => { $vis struct $name; }; + ($vis:vis trait $name:ident {}) => { $vis trait $name {} }; + ($vis:vis type $name:ident = $ty:ty;) => { $vis type $name = $ty; }; + ($vis:vis use $path:ident as $name:ident;) => { $vis use self::$path as $name; }; +} + +mod with_pub { + vis_passthru! { pub const A: i32 = 0; } + vis_passthru! { pub enum B {} } + vis_passthru! { pub extern "C" fn c() {} } + vis_passthru! { pub mod d {} } + vis_passthru! { pub static E: i32 = 0; } + vis_passthru! { pub struct F; } + vis_passthru! { pub trait G {} } + vis_passthru! { pub type H = i32; } + vis_passthru! { pub use A as I; } +} + +mod without_pub { + vis_passthru! { const A: i32 = 0; } + vis_passthru! { enum B {} } + vis_passthru! { extern "C" fn c() {} } + vis_passthru! { mod d {} } + vis_passthru! { static E: i32 = 0; } + vis_passthru! { struct F; } + vis_passthru! { trait G {} } + vis_passthru! { type H = i32; } + vis_passthru! { use A as I; } +} + +mod with_pub_restricted { + vis_passthru! { pub(crate) const A: i32 = 0; } + vis_passthru! { pub(crate) enum B {} } + vis_passthru! { pub(crate) extern "C" fn c() {} } + vis_passthru! { pub(crate) mod d {} } + vis_passthru! { pub(crate) static E: i32 = 0; } + vis_passthru! { pub(crate) struct F; } + vis_passthru! { pub(crate) trait G {} } + vis_passthru! { pub(crate) type H = i32; } + vis_passthru! { pub(crate) use A as I; } +} + +mod garden { + mod with_pub_restricted_path { + vis_passthru! { pub(::garden) const A: i32 = 0; } + vis_passthru! { pub(::garden) enum B {} } + vis_passthru! { pub(::garden) extern "C" fn c() {} } + vis_passthru! { pub(::garden) mod d {} } + vis_passthru! { pub(::garden) static E: i32 = 0; } + vis_passthru! { pub(::garden) struct F; } + vis_passthru! { pub(::garden) trait G {} } + vis_passthru! { pub(::garden) type H = i32; } + vis_passthru! { pub(::garden) use A as I; } + } +} + +/* +Ensure that the `:vis` matcher works in a more complex situation: parsing a +struct definition. +*/ +macro_rules! vis_parse_struct { + /* + The rule duplication is currently unavoidable due to the leading attribute + matching. + */ + ($(#[$($attrs:tt)*])* pub($($vis:tt)*) struct $name:ident {$($body:tt)*}) => { + vis_parse_struct! { @parse_fields $(#[$($attrs)*])*, pub($($vis)*), $name, $($body)* } + }; + ($(#[$($attrs:tt)*])* pub struct $name:ident {$($body:tt)*}) => { + vis_parse_struct! { @parse_fields $(#[$($attrs)*])*, pub, $name, $($body)* } + }; + ($(#[$($attrs:tt)*])* struct $name:ident {$($body:tt)*}) => { + vis_parse_struct! { @parse_fields $(#[$($attrs)*])*, , $name, $($body)* } + }; + + ($(#[$($attrs:tt)*])* pub($($vis:tt)*) struct $name:ident ($($body:tt)*);) => { + vis_parse_struct! { @parse_tuple $(#[$($attrs)*])*, pub($($vis)*), $name, $($body)* } + }; + ($(#[$($attrs:tt)*])* pub struct $name:ident ($($body:tt)*);) => { + vis_parse_struct! { @parse_tuple $(#[$($attrs)*])*, pub, $name, $($body)* } + }; + ($(#[$($attrs:tt)*])* struct $name:ident ($($body:tt)*);) => { + vis_parse_struct! { @parse_tuple $(#[$($attrs)*])*, , $name, $($body)* } + }; + + (@parse_fields $(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fname:ident: $fty:ty),* $(,)*) => { + $(#[$attrs])* $vis struct $name { $($fvis $fname: $fty,)* } + }; + + (@parse_tuple $(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fty:ty),* $(,)*) => { + $(#[$attrs])* $vis struct $name ( $($fvis $fty,)* ); + }; +} + +mod test_struct { + vis_parse_struct! { pub(crate) struct A { pub a: i32, b: i32, pub(crate) c: i32 } } + vis_parse_struct! { pub struct B { a: i32, pub(crate) b: i32, pub c: i32 } } + vis_parse_struct! { struct C { pub(crate) a: i32, pub b: i32, c: i32 } } + + vis_parse_struct! { pub(crate) struct D (pub i32, i32, pub(crate) i32); } + vis_parse_struct! { pub struct E (i32, pub(crate) i32, pub i32); } + vis_parse_struct! { struct F (pub(crate) i32, pub i32, i32); } +} + +fn main() {} -- cgit 1.4.1-3-g733a5 From d53e413e04e438fd0dc1a8b1a8dcb07a0774092a Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sun, 2 Apr 2017 04:21:12 +0000 Subject: update :vis implementation to current rust --- src/libsyntax/ext/tt/macro_rules.rs | 12 ++++++------ src/libsyntax/parse/parser.rs | 2 +- src/test/run-pass/macro-pub-matcher.rs | 19 +++++++++---------- 3 files changed, 16 insertions(+), 17 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 4e197a85ebd..f888e29bdab 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -793,13 +793,13 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result { // Explicitly disallow `priv`, on the off chance it comes back. match *tok { - Comma => Ok(true), - ModSep => Ok(true), - MatchNt(_, ref frag, _, _) => { - let name = frag.name.as_str(); - Ok(name == "ident" || name == "ty") + TokenTree::Token(_, ref tok) => match *tok { + Comma => Ok(true), + ModSep => Ok(true), + Ident(i) if i.name != "priv" => Ok(true), + _ => Ok(false) }, - Ident(i, _) if i.name.as_str() != "priv" => Ok(true), + TokenTree::MetaVarDecl(_, _, frag) if frag.name =="ident" || frag.name == "ty" => Ok(true), _ => Ok(false) } }, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 3b928ea93c7..11becd58293 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5056,7 +5056,7 @@ impl<'a> Parser<'a> { /// and `pub(super)` for `pub(in super)`. If the following element can't be a tuple (i.e. it's /// a function definition, it's not a tuple struct field) and the contents within the parens /// isn't valid, emit a proper diagnostic. - fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> { + pub fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> { if !self.eat_keyword(keywords::Pub) { return Ok(Visibility::Inherited) } diff --git a/src/test/run-pass/macro-pub-matcher.rs b/src/test/run-pass/macro-pub-matcher.rs index 64fa0bef464..7de9cc6bf21 100644 --- a/src/test/run-pass/macro-pub-matcher.rs +++ b/src/test/run-pass/macro-pub-matcher.rs @@ -1,5 +1,4 @@ #![allow(dead_code, unused_imports)] -#![feature(pub_restricted)] /** Ensure that `:vis` matches can be captured in existing positions, and passed @@ -56,15 +55,15 @@ mod with_pub_restricted { mod garden { mod with_pub_restricted_path { - vis_passthru! { pub(::garden) const A: i32 = 0; } - vis_passthru! { pub(::garden) enum B {} } - vis_passthru! { pub(::garden) extern "C" fn c() {} } - vis_passthru! { pub(::garden) mod d {} } - vis_passthru! { pub(::garden) static E: i32 = 0; } - vis_passthru! { pub(::garden) struct F; } - vis_passthru! { pub(::garden) trait G {} } - vis_passthru! { pub(::garden) type H = i32; } - vis_passthru! { pub(::garden) use A as I; } + vis_passthru! { pub(in garden) const A: i32 = 0; } + vis_passthru! { pub(in garden) enum B {} } + vis_passthru! { pub(in garden) extern "C" fn c() {} } + vis_passthru! { pub(in garden) mod d {} } + vis_passthru! { pub(in garden) static E: i32 = 0; } + vis_passthru! { pub(in garden) struct F; } + vis_passthru! { pub(in garden) trait G {} } + vis_passthru! { pub(in garden) type H = i32; } + vis_passthru! { pub(in garden) use A as I; } } } -- cgit 1.4.1-3-g733a5 From 16010c2f50dd92cc57ccced270a9fb727d6d4883 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sun, 2 Apr 2017 04:46:51 +0000 Subject: parse interpolated visibility tokens --- src/libsyntax/ext/tt/macro_rules.rs | 3 ++- src/libsyntax/parse/parser.rs | 2 ++ src/test/run-pass/macro-pub-matcher.rs | 16 ++++++++++++++-- 3 files changed, 18 insertions(+), 3 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index f888e29bdab..84c909284a8 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -799,7 +799,8 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result Ok(true), _ => Ok(false) }, - TokenTree::MetaVarDecl(_, _, frag) if frag.name =="ident" || frag.name == "ty" => Ok(true), + TokenTree::MetaVarDecl(_, _, frag) + if frag.name =="ident" || frag.name == "ty" => Ok(true), _ => Ok(false) } }, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 11becd58293..31669e1bbe3 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5057,6 +5057,8 @@ impl<'a> Parser<'a> { /// a function definition, it's not a tuple struct field) and the contents within the parens /// isn't valid, emit a proper diagnostic. pub fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> { + maybe_whole!(self, NtVis, |x| x); + if !self.eat_keyword(keywords::Pub) { return Ok(Visibility::Inherited) } diff --git a/src/test/run-pass/macro-pub-matcher.rs b/src/test/run-pass/macro-pub-matcher.rs index 7de9cc6bf21..d5b25e6cdf2 100644 --- a/src/test/run-pass/macro-pub-matcher.rs +++ b/src/test/run-pass/macro-pub-matcher.rs @@ -1,3 +1,13 @@ +// Copyright 2017 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. + #![allow(dead_code, unused_imports)] /** @@ -96,11 +106,13 @@ macro_rules! vis_parse_struct { vis_parse_struct! { @parse_tuple $(#[$($attrs)*])*, , $name, $($body)* } }; - (@parse_fields $(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fname:ident: $fty:ty),* $(,)*) => { + (@parse_fields + $(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fname:ident: $fty:ty),* $(,)*) => { $(#[$attrs])* $vis struct $name { $($fvis $fname: $fty,)* } }; - (@parse_tuple $(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fty:ty),* $(,)*) => { + (@parse_tuple + $(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fty:ty),* $(,)*) => { $(#[$attrs])* $vis struct $name ( $($fvis $fty,)* ); }; } -- cgit 1.4.1-3-g733a5 From 06d32335e893a1b5af5dd3f6a8a53dcae266a016 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sun, 2 Apr 2017 18:34:38 +0000 Subject: move NtVis enum variant to stave off comment rot --- src/libsyntax/parse/token.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 513aa866043..25cabef70c1 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -363,6 +363,7 @@ pub enum Nonterminal { /// Stuff inside brackets for attributes NtMeta(ast::MetaItem), NtPath(ast::Path), + NtVis(ast::Visibility), NtTT(TokenTree), // These are not exposed to macros, but are used by quasiquote. NtArm(ast::Arm), @@ -371,7 +372,6 @@ pub enum Nonterminal { NtGenerics(ast::Generics), NtWhereClause(ast::WhereClause), NtArg(ast::Arg), - NtVis(ast::Visibility), } impl fmt::Debug for Nonterminal { -- cgit 1.4.1-3-g733a5 From 08a955af68ae350dabb7b66b4981f4503ba74aa3 Mon Sep 17 00:00:00 2001 From: alexey zabelin Date: Mon, 17 Apr 2017 10:48:23 -0400 Subject: Adjust description --- src/libsyntax/parse/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 0fddbca72cd..ab4ac6f1b91 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4066,7 +4066,7 @@ impl<'a> Parser<'a> { }).emit(); } - // Parse bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. + // Parse bounds of a type parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. // BOUND = TY_BOUND | LT_BOUND // LT_BOUND = LIFETIME (e.g. `'a`) // TY_BOUND = [?] [for] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) -- cgit 1.4.1-3-g733a5 From d648c10e5bc313af758951c1e6f8ae4782712627 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 13 Apr 2017 22:37:05 +0300 Subject: libsyntax/parse: improve associated item error reporting Fixes #41161. Fixes #41239. --- src/libsyntax/ext/expand.rs | 4 +- src/libsyntax/parse/parser.rs | 167 ++++++++++++++++----------- src/test/parse-fail/issue-21153.rs | 5 +- src/test/parse-fail/trait-pub-assoc-const.rs | 2 +- src/test/parse-fail/trait-pub-assoc-ty.rs | 2 +- src/test/parse-fail/trait-pub-method.rs | 2 +- src/test/ui/did_you_mean/issue-40006.rs | 12 ++ src/test/ui/did_you_mean/issue-40006.stderr | 68 ++++++++++- src/test/ui/token/issue-41155.stderr | 10 +- 9 files changed, 191 insertions(+), 81 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1b3352f73ad..20a858b80df 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -617,14 +617,14 @@ impl<'a> Parser<'a> { ExpansionKind::TraitItems => { let mut items = SmallVector::new(); while self.token != token::Eof { - items.push(self.parse_trait_item()?); + items.push(self.parse_trait_item(&mut false)?); } Expansion::TraitItems(items) } ExpansionKind::ImplItems => { let mut items = SmallVector::new(); while self.token != token::Eof { - items.push(self.parse_impl_item()?); + items.push(self.parse_impl_item(&mut false)?); } Expansion::ImplItems(items) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 58be43526fd..dfb82d40d56 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -85,12 +85,18 @@ pub enum PathStyle { Expr, } -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum SemiColonMode { Break, Ignore, } +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum BlockMode { + Break, + Ignore, +} + /// Possibly accept an `token::Interpolated` expression (a pre-parsed expression /// dropped into the token stream, which happens while parsing the result of /// macro expansion). Placement of these is not as complex as I feared it would @@ -1204,7 +1210,7 @@ impl<'a> Parser<'a> { } /// Parse the items in a trait declaration - pub fn parse_trait_item(&mut self) -> PResult<'a, TraitItem> { + pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, TraitItem> { maybe_whole!(self, NtTraitItem, |x| x); let mut attrs = self.parse_outer_attributes()?; let lo = self.span; @@ -1214,7 +1220,7 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)?; (ident, TraitItemKind::Type(bounds, default)) } else if self.is_const_item() { - self.expect_keyword(keywords::Const)?; + self.expect_keyword(keywords::Const)?; let ident = self.parse_ident()?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; @@ -1231,9 +1237,17 @@ impl<'a> Parser<'a> { } else if self.token.is_path_start() { // trait item macro. // code copied from parse_macro_use_or_failure... abstraction! + let prev_span = self.prev_span; let lo = self.span; let pth = self.parse_path(PathStyle::Mod)?; - self.expect(&token::Not)?; + + if pth.segments.len() == 1 { + if !self.eat(&token::Not) { + return Err(self.missing_assoc_item_kind_err("trait", prev_span)); + } + } else { + self.expect(&token::Not)?; + } // eat a matched-delimiter token tree: let (delim, tts) = self.expect_delimited_token_tree()?; @@ -1246,25 +1260,7 @@ impl<'a> Parser<'a> { } else { let (constness, unsafety, abi) = match self.parse_fn_front_matter() { Ok(cua) => cua, - Err(e) => { - loop { - match self.token { - token::Eof => break, - token::CloseDelim(token::Brace) | - token::Semi => { - self.bump(); - break; - } - token::OpenDelim(token::Brace) => { - self.parse_token_tree(); - break; - } - _ => self.bump(), - } - } - - return Err(e); - } + Err(e) => return Err(e), }; let ident = self.parse_ident()?; @@ -1289,11 +1285,13 @@ impl<'a> Parser<'a> { let body = match self.token { token::Semi => { self.bump(); + *at_end = true; debug!("parse_trait_methods(): parsing required method"); None } token::OpenDelim(token::Brace) => { debug!("parse_trait_methods(): parsing provided method"); + *at_end = true; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(inner_attrs.iter().cloned()); Some(body) @@ -1315,18 +1313,6 @@ impl<'a> Parser<'a> { }) } - - /// Parse the items in a trait declaration - pub fn parse_trait_items(&mut self) -> PResult<'a, Vec> { - self.parse_unspanned_seq( - &token::OpenDelim(token::Brace), - &token::CloseDelim(token::Brace), - SeqSep::none(), - |p| -> PResult<'a, TraitItem> { - p.parse_trait_item() - }) - } - /// Parse optional return type [ -> TY ] in function decl pub fn parse_ret_ty(&mut self) -> PResult<'a, FunctionRetTy> { if self.eat(&token::RArrow) { @@ -3641,22 +3627,33 @@ impl<'a> Parser<'a> { // // We terminate when we find an unmatched `}` (without consuming it). fn recover_stmt(&mut self) { - self.recover_stmt_(SemiColonMode::Ignore) + self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore) } + // If `break_on_semi` is `Break`, then we will stop consuming tokens after // finding (and consuming) a `;` outside of `{}` or `[]` (note that this is // approximate - it can mean we break too early due to macros, but that // shoud only lead to sub-optimal recovery, not inaccurate parsing). - fn recover_stmt_(&mut self, break_on_semi: SemiColonMode) { + // + // If `break_on_block` is `Break`, then we will stop consuming tokens + // after finding (and consuming) a brace-delimited block. + fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) { let mut brace_depth = 0; let mut bracket_depth = 0; - debug!("recover_stmt_ enter loop"); + let mut in_block = false; + debug!("recover_stmt_ enter loop (semi={:?}, block={:?})", + break_on_semi, break_on_block); loop { debug!("recover_stmt_ loop {:?}", self.token); match self.token { token::OpenDelim(token::DelimToken::Brace) => { brace_depth += 1; self.bump(); + if break_on_block == BlockMode::Break && + brace_depth == 1 && + bracket_depth == 0 { + in_block = true; + } } token::OpenDelim(token::DelimToken::Bracket) => { bracket_depth += 1; @@ -3669,6 +3666,10 @@ impl<'a> Parser<'a> { } brace_depth -= 1; self.bump(); + if in_block && bracket_depth == 0 && brace_depth == 0 { + debug!("recover_stmt_ return - block end {:?}", self.token); + return; + } } token::CloseDelim(token::DelimToken::Bracket) => { bracket_depth -= 1; @@ -3700,7 +3701,7 @@ impl<'a> Parser<'a> { fn parse_stmt_(&mut self, macro_legacy_warnings: bool) -> Option { self.parse_stmt_without_recovery(macro_legacy_warnings).unwrap_or_else(|mut e| { e.emit(); - self.recover_stmt_(SemiColonMode::Break); + self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); None }) } @@ -3974,7 +3975,7 @@ impl<'a> Parser<'a> { e.span_suggestion(stmt_span, "try placing this code inside a block", sugg); } Err(mut e) => { - self.recover_stmt_(SemiColonMode::Break); + self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); self.cancel(&mut e); } _ => () @@ -4663,7 +4664,7 @@ impl<'a> Parser<'a> { } /// Parse an impl item. - pub fn parse_impl_item(&mut self) -> PResult<'a, ImplItem> { + pub fn parse_impl_item(&mut self, at_end: &mut bool) -> PResult<'a, ImplItem> { maybe_whole!(self, NtImplItem, |x| x); let mut attrs = self.parse_outer_attributes()?; @@ -4686,7 +4687,7 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)?; (name, ast::ImplItemKind::Const(typ, expr)) } else { - let (name, inner_attrs, node) = self.parse_impl_method(&vis)?; + let (name, inner_attrs, node) = self.parse_impl_method(&vis, at_end)?; attrs.extend(inner_attrs); (name, node) }; @@ -4731,43 +4732,50 @@ impl<'a> Parser<'a> { } } + fn missing_assoc_item_kind_err(&mut self, item_type: &str, prev_span: Span) + -> DiagnosticBuilder<'a> + { + // Given this code `path(`, it seems like this is not + // setting the visibility of a macro invocation, but rather + // a mistyped method declaration. + // Create a diagnostic pointing out that `fn` is missing. + // + // x | pub path(&self) { + // | ^ missing `fn`, `type`, or `const` + // pub path( + // ^^ `sp` below will point to this + let sp = prev_span.between(self.prev_span); + let mut err = self.diagnostic().struct_span_err( + sp, + &format!("missing `fn`, `type`, or `const` for {}-item declaration", + item_type)); + err.span_label(sp, &"missing `fn`, `type`, or `const`"); + err + } + /// Parse a method or a macro invocation in a trait impl. - fn parse_impl_method(&mut self, vis: &Visibility) + fn parse_impl_method(&mut self, vis: &Visibility, at_end: &mut bool) -> PResult<'a, (Ident, Vec, ast::ImplItemKind)> { // code copied from parse_macro_use_or_failure... abstraction! if self.token.is_path_start() { // Method macro. let prev_span = self.prev_span; - // Before complaining about trying to set a macro as `pub`, - // check if `!` comes after the path. - let err = self.complain_if_pub_macro_diag(&vis, prev_span); let lo = self.span; let pth = self.parse_path(PathStyle::Mod)?; - let bang_err = self.expect(&token::Not); - if let Err(mut err) = err { - if let Err(mut bang_err) = bang_err { - // Given this code `pub path(`, it seems like this is not setting the - // visibility of a macro invocation, but rather a mistyped method declaration. - // Create a diagnostic pointing out that `fn` is missing. - // - // x | pub path(&self) { - // | ^ missing `fn` for method declaration - - err.cancel(); - bang_err.cancel(); - // pub path( - // ^^ `sp` below will point to this - let sp = prev_span.between(self.prev_span); - err = self.diagnostic() - .struct_span_err(sp, "missing `fn` for method declaration"); - err.span_label(sp, &"missing `fn`"); + if pth.segments.len() == 1 { + if !self.eat(&token::Not) { + return Err(self.missing_assoc_item_kind_err("impl", prev_span)); } - return Err(err); + } else { + self.expect(&token::Not)?; } + self.complain_if_pub_macro(&vis, prev_span); + // eat a matched-delimiter token tree: + *at_end = true; let (delim, tts) = self.expect_delimited_token_tree()?; if delim != token::Brace { self.expect(&token::Semi)? @@ -4781,6 +4789,7 @@ impl<'a> Parser<'a> { let mut generics = self.parse_generics()?; let decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?; generics.where_clause = self.parse_where_clause()?; + *at_end = true; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; Ok((ident, inner_attrs, ast::ImplItemKind::Method(ast::MethodSig { generics: generics, @@ -4806,8 +4815,21 @@ impl<'a> Parser<'a> { tps.where_clause = self.parse_where_clause()?; - let meths = self.parse_trait_items()?; - Ok((ident, ItemKind::Trait(unsafety, tps, bounds, meths), None)) + self.expect(&token::OpenDelim(token::Brace))?; + let mut trait_items = vec![]; + while !self.eat(&token::CloseDelim(token::Brace)) { + let mut at_end = false; + match self.parse_trait_item(&mut at_end) { + Ok(item) => trait_items.push(item), + Err(mut e) => { + e.emit(); + if !at_end { + self.recover_stmt_(SemiColonMode::Break, BlockMode::Break); + } + } + } + } + Ok((ident, ItemKind::Trait(unsafety, tps, bounds, trait_items), None)) } /// Parses items implementations variants @@ -4882,7 +4904,16 @@ impl<'a> Parser<'a> { let mut impl_items = vec![]; while !self.eat(&token::CloseDelim(token::Brace)) { - impl_items.push(self.parse_impl_item()?); + let mut at_end = false; + match self.parse_impl_item(&mut at_end) { + Ok(item) => impl_items.push(item), + Err(mut e) => { + e.emit(); + if !at_end { + self.recover_stmt_(SemiColonMode::Break, BlockMode::Break); + } + } + } } Ok((keywords::Invalid.ident(), diff --git a/src/test/parse-fail/issue-21153.rs b/src/test/parse-fail/issue-21153.rs index c03e0ef7321..b6d95ffb911 100644 --- a/src/test/parse-fail/issue-21153.rs +++ b/src/test/parse-fail/issue-21153.rs @@ -10,7 +10,6 @@ // compile-flags: -Z parse-only -trait MyTrait: Iterator { - Item = T; //~ ERROR expected one of `!` or `::`, found `=` - //~| ERROR expected item, found `=` +trait MyTrait: Iterator { //~ ERROR missing `fn`, `type`, or `const` + Item = T; } diff --git a/src/test/parse-fail/trait-pub-assoc-const.rs b/src/test/parse-fail/trait-pub-assoc-const.rs index adce0d7bbf4..6bc24e2081d 100644 --- a/src/test/parse-fail/trait-pub-assoc-const.rs +++ b/src/test/parse-fail/trait-pub-assoc-const.rs @@ -10,7 +10,7 @@ trait Foo { pub const Foo: u32; - //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub` + //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub` } fn main() {} diff --git a/src/test/parse-fail/trait-pub-assoc-ty.rs b/src/test/parse-fail/trait-pub-assoc-ty.rs index dab6c433aba..493ff087eaf 100644 --- a/src/test/parse-fail/trait-pub-assoc-ty.rs +++ b/src/test/parse-fail/trait-pub-assoc-ty.rs @@ -10,7 +10,7 @@ trait Foo { pub type Foo; - //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub` + //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub` } fn main() {} diff --git a/src/test/parse-fail/trait-pub-method.rs b/src/test/parse-fail/trait-pub-method.rs index 7cb9363830c..c2ee3c31d88 100644 --- a/src/test/parse-fail/trait-pub-method.rs +++ b/src/test/parse-fail/trait-pub-method.rs @@ -10,7 +10,7 @@ trait Foo { pub fn foo(); - //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub` + //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub` } fn main() {} diff --git a/src/test/ui/did_you_mean/issue-40006.rs b/src/test/ui/did_you_mean/issue-40006.rs index cf75929bae2..d68c25faa8a 100644 --- a/src/test/ui/did_you_mean/issue-40006.rs +++ b/src/test/ui/did_you_mean/issue-40006.rs @@ -8,8 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +impl X { + Y +} + struct S; +trait X { + X() {} + fn xxx() { ### } + L = M; + Z = { 2 + 3 }; + ::Y (); +} + impl S { pub hello_method(&self) { println!("Hello"); diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr index 460958027ad..29ff0cee3af 100644 --- a/src/test/ui/did_you_mean/issue-40006.stderr +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -1,8 +1,68 @@ -error: missing `fn` for method declaration - --> $DIR/issue-40006.rs:14:8 +error: missing `fn`, `type`, or `const` for impl-item declaration + --> $DIR/issue-40006.rs:11:9 | -14 | pub hello_method(&self) { - | ^ missing `fn` +11 | impl X { + | _________^ starting here... +12 | | Y + | |____^ ...ending here: missing `fn`, `type`, or `const` + +error: missing `fn`, `type`, or `const` for trait-item declaration + --> $DIR/issue-40006.rs:17:10 + | +17 | trait X { + | __________^ starting here... +18 | | X() {} + | |____^ ...ending here: missing `fn`, `type`, or `const` + +error: expected `[`, found `#` + --> $DIR/issue-40006.rs:19:17 + | +19 | fn xxx() { ### } + | ^ + +error: missing `fn`, `type`, or `const` for trait-item declaration + --> $DIR/issue-40006.rs:19:21 + | +19 | fn xxx() { ### } + | _____________________^ starting here... +20 | | L = M; + | |____^ ...ending here: missing `fn`, `type`, or `const` + +error: missing `fn`, `type`, or `const` for trait-item declaration + --> $DIR/issue-40006.rs:20:11 + | +20 | L = M; + | ___________^ starting here... +21 | | Z = { 2 + 3 }; + | |____^ ...ending here: missing `fn`, `type`, or `const` + +error: expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;` + --> $DIR/issue-40006.rs:21:18 + | +21 | Z = { 2 + 3 }; + | ^ expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}` here + +error: expected one of `!` or `::`, found `(` + --> $DIR/issue-40006.rs:22:9 + | +22 | ::Y (); + | -^ unexpected token + | | + | expected one of `!` or `::` here + +error: missing `fn`, `type`, or `const` for impl-item declaration + --> $DIR/issue-40006.rs:26:8 + | +26 | pub hello_method(&self) { + | ^ missing `fn`, `type`, or `const` + +error[E0038]: the trait `X` cannot be made into an object + --> $DIR/issue-40006.rs:11:6 + | +11 | impl X { + | ^ the trait `X` cannot be made into an object + | + = note: method `xxx` has no receiver error: aborting due to previous error diff --git a/src/test/ui/token/issue-41155.stderr b/src/test/ui/token/issue-41155.stderr index 0da3abd4eaf..a6ad1206b14 100644 --- a/src/test/ui/token/issue-41155.stderr +++ b/src/test/ui/token/issue-41155.stderr @@ -6,5 +6,13 @@ error: expected one of `(`, `const`, `default`, `extern`, `fn`, `type`, or `unsa 13 | } | ^ unexpected token -error: aborting due to previous error +error[E0412]: cannot find type `S` in this scope + --> $DIR/issue-41155.rs:11:6 + | +11 | impl S { + | ^ not found in this scope + +error: main function not found + +error: aborting due to 3 previous errors -- cgit 1.4.1-3-g733a5 From e038f58105cc1769a9c7991981822d01ebffe277 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 5 Apr 2017 01:12:53 +0300 Subject: syntax: Support parentheses around trait bounds --- src/libsyntax/parse/parser.rs | 29 +++++++++++++++++++--- src/test/parse-fail/trait-object-bad-parens.rs | 20 +++++++++++++++ .../parse-fail/trait-object-lifetime-parens.rs | 18 ++++++++++++++ src/test/parse-fail/trait-object-trait-parens.rs | 21 ++++++++++++++++ 4 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 src/test/parse-fail/trait-object-bad-parens.rs create mode 100644 src/test/parse-fail/trait-object-lifetime-parens.rs create mode 100644 src/test/parse-fail/trait-object-trait-parens.rs (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 0cdb09a842f..1232411d1ec 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -152,6 +152,7 @@ fn maybe_append(mut lhs: Vec, rhs: Option>) enum PrevTokenKind { DocComment, Comma, + Plus, Interpolated, Eof, Other, @@ -1061,6 +1062,7 @@ impl<'a> Parser<'a> { self.prev_token_kind = match self.token { token::DocComment(..) => PrevTokenKind::DocComment, token::Comma => PrevTokenKind::Comma, + token::BinOp(token::Plus) => PrevTokenKind::Plus, token::Interpolated(..) => PrevTokenKind::Interpolated, token::Eof => PrevTokenKind::Eof, _ => PrevTokenKind::Other, @@ -1354,20 +1356,29 @@ impl<'a> Parser<'a> { break; } } + let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus; self.expect(&token::CloseDelim(token::Paren))?; if ts.len() == 1 && !last_comma { let ty = ts.into_iter().nth(0).unwrap().unwrap(); + let maybe_bounds = allow_plus && self.token == token::BinOp(token::Plus); match ty.node { - // Accept `(Trait1) + Trait2 + 'a` for backward compatibility (#39318). - TyKind::Path(None, ref path) - if allow_plus && self.token == token::BinOp(token::Plus) => { + // `(TY_BOUND_NOPAREN) + BOUND + ...`. + TyKind::Path(None, ref path) if maybe_bounds => { self.bump(); // `+` let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo.to(self.prev_span)); let mut bounds = vec![TraitTyParamBound(pt, TraitBoundModifier::None)]; bounds.append(&mut self.parse_ty_param_bounds()?); TyKind::TraitObject(bounds) } + TyKind::TraitObject(ref bounds) + if maybe_bounds && bounds.len() == 1 && !trailing_plus => { + self.bump(); // `+` + let mut bounds = bounds.clone(); + bounds.append(&mut self.parse_ty_param_bounds()?); + TyKind::TraitObject(bounds) + } + // `(TYPE)` _ => TyKind::Paren(P(ty)) } } else { @@ -4070,10 +4081,12 @@ impl<'a> Parser<'a> { // Parse bounds of a type parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. // BOUND = TY_BOUND | LT_BOUND // LT_BOUND = LIFETIME (e.g. `'a`) - // TY_BOUND = [?] [for] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) + // TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) + // TY_BOUND_NOPAREN = [?] [for] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> { let mut bounds = Vec::new(); loop { + let has_parens = self.eat(&token::OpenDelim(token::Paren)); let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; if self.check_lifetime() { if let Some(question_span) = question { @@ -4081,6 +4094,11 @@ impl<'a> Parser<'a> { "`?` may only modify trait bounds, not lifetime bounds"); } bounds.push(RegionTyParamBound(self.expect_lifetime())); + if has_parens { + self.expect(&token::CloseDelim(token::Paren))?; + self.span_err(self.prev_span, + "parenthesized lifetime bounds are not supported"); + } } else if self.check_keyword(keywords::For) || self.check_path() { let lo = self.span; let lifetime_defs = self.parse_late_bound_lifetime_defs()?; @@ -4092,6 +4110,9 @@ impl<'a> Parser<'a> { TraitBoundModifier::None }; bounds.push(TraitTyParamBound(poly_trait, modifier)); + if has_parens { + self.expect(&token::CloseDelim(token::Paren))?; + } } else { break } diff --git a/src/test/parse-fail/trait-object-bad-parens.rs b/src/test/parse-fail/trait-object-bad-parens.rs new file mode 100644 index 00000000000..a44c0c3f32f --- /dev/null +++ b/src/test/parse-fail/trait-object-bad-parens.rs @@ -0,0 +1,20 @@ +// Copyright 2017 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 -Z continue-parse-after-error + +fn main() { + let _: Box<((Copy)) + Copy>; + //~^ ERROR expected a path on the left-hand side of `+`, not `((Copy))` + let _: Box<(Copy + Copy) + Copy>; + //~^ ERROR expected a path on the left-hand side of `+`, not `( Copy + Copy)` + let _: Box<(Copy +) + Copy>; + //~^ ERROR expected a path on the left-hand side of `+`, not `( Copy)` +} diff --git a/src/test/parse-fail/trait-object-lifetime-parens.rs b/src/test/parse-fail/trait-object-lifetime-parens.rs new file mode 100644 index 00000000000..6be62d966eb --- /dev/null +++ b/src/test/parse-fail/trait-object-lifetime-parens.rs @@ -0,0 +1,18 @@ +// Copyright 2017 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 -Z continue-parse-after-error + +fn f() {} //~ ERROR parenthesized lifetime bounds are not supported + +fn main() { + let _: Box; //~ ERROR parenthesized lifetime bounds are not supported + let _: Box<('a) + Copy>; //~ ERROR expected type, found `'a` +} diff --git a/src/test/parse-fail/trait-object-trait-parens.rs b/src/test/parse-fail/trait-object-trait-parens.rs new file mode 100644 index 00000000000..dc44f4f3fb1 --- /dev/null +++ b/src/test/parse-fail/trait-object-trait-parens.rs @@ -0,0 +1,21 @@ +// Copyright 2017 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 + +fn f Trait<'a>)>() {} + +fn main() { + let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>; + let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Copy)>; + let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>; +} + +FAIL //~ ERROR -- cgit 1.4.1-3-g733a5 From 6e75def7dba6ee28660b8479f0ede72986c299f7 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 21 Apr 2017 00:19:06 +0300 Subject: Fix issue with single question mark or paren --- src/doc/grammar.md | 5 ++- src/libsyntax/parse/parser.rs | 51 +++++++++++++---------- src/test/parse-fail/bound-single-question-mark.rs | 13 ++++++ 3 files changed, 44 insertions(+), 25 deletions(-) create mode 100644 src/test/parse-fail/bound-single-question-mark.rs (limited to 'src/libsyntax/parse') diff --git a/src/doc/grammar.md b/src/doc/grammar.md index 3fbf9f06d99..12daa24e857 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -781,10 +781,11 @@ never_type : "!" ; ### Type parameter bounds ```antlr +bound-list := bound | bound '+' bound-list '+' ? bound := ty_bound | lt_bound lt_bound := lifetime -ty_bound := [?] [ for ] simple_path -bound-list := bound | bound '+' bound-list '+' ? +ty_bound := ty_bound_noparen | (ty_bound_noparen) +ty_bound_noparen := [?] [ for ] simple_path ``` ### Self types diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 1232411d1ec..79ae1d62915 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4086,32 +4086,37 @@ impl<'a> Parser<'a> { fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> { let mut bounds = Vec::new(); loop { - let has_parens = self.eat(&token::OpenDelim(token::Paren)); - let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; - if self.check_lifetime() { - if let Some(question_span) = question { - self.span_err(question_span, - "`?` may only modify trait bounds, not lifetime bounds"); - } - bounds.push(RegionTyParamBound(self.expect_lifetime())); - if has_parens { - self.expect(&token::CloseDelim(token::Paren))?; - self.span_err(self.prev_span, - "parenthesized lifetime bounds are not supported"); - } - } else if self.check_keyword(keywords::For) || self.check_path() { - let lo = self.span; - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - let path = self.parse_path(PathStyle::Type)?; - let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); - let modifier = if question.is_some() { - TraitBoundModifier::Maybe + let is_bound_start = self.check_path() || self.check_lifetime() || + self.check(&token::Question) || + self.check_keyword(keywords::For) || + self.check(&token::OpenDelim(token::Paren)); + if is_bound_start { + let has_parens = self.eat(&token::OpenDelim(token::Paren)); + let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; + if self.token.is_lifetime() { + if let Some(question_span) = question { + self.span_err(question_span, + "`?` may only modify trait bounds, not lifetime bounds"); + } + bounds.push(RegionTyParamBound(self.expect_lifetime())); } else { - TraitBoundModifier::None - }; - bounds.push(TraitTyParamBound(poly_trait, modifier)); + let lo = self.span; + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let path = self.parse_path(PathStyle::Type)?; + let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); + let modifier = if question.is_some() { + TraitBoundModifier::Maybe + } else { + TraitBoundModifier::None + }; + bounds.push(TraitTyParamBound(poly_trait, modifier)); + } if has_parens { self.expect(&token::CloseDelim(token::Paren))?; + if let Some(&RegionTyParamBound(..)) = bounds.last() { + self.span_err(self.prev_span, + "parenthesized lifetime bounds are not supported"); + } } } else { break diff --git a/src/test/parse-fail/bound-single-question-mark.rs b/src/test/parse-fail/bound-single-question-mark.rs new file mode 100644 index 00000000000..9dde5268c08 --- /dev/null +++ b/src/test/parse-fail/bound-single-question-mark.rs @@ -0,0 +1,13 @@ +// Copyright 2017 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 + +fn f() {} //~ ERROR expected identifier, found `>` -- cgit 1.4.1-3-g733a5 From 8838cd10f2374ed51c4b219c1f070d0c29af3b86 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 21 Apr 2017 21:32:11 +0300 Subject: Move parse_remaining_bounds into a separate function --- src/libsyntax/parse/parser.rs | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 79ae1d62915..1baf0d1b54c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1365,18 +1365,15 @@ impl<'a> Parser<'a> { match ty.node { // `(TY_BOUND_NOPAREN) + BOUND + ...`. TyKind::Path(None, ref path) if maybe_bounds => { - self.bump(); // `+` - let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo.to(self.prev_span)); - let mut bounds = vec![TraitTyParamBound(pt, TraitBoundModifier::None)]; - bounds.append(&mut self.parse_ty_param_bounds()?); - TyKind::TraitObject(bounds) + self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)? } TyKind::TraitObject(ref bounds) if maybe_bounds && bounds.len() == 1 && !trailing_plus => { - self.bump(); // `+` - let mut bounds = bounds.clone(); - bounds.append(&mut self.parse_ty_param_bounds()?); - TyKind::TraitObject(bounds) + let path = match bounds[0] { + TraitTyParamBound(ref pt, ..) => pt.trait_ref.path.clone(), + _ => self.bug("unexpected lifetime bound"), + }; + self.parse_remaining_bounds(Vec::new(), path, lo, true)? } // `(TYPE)` _ => TyKind::Paren(P(ty)) @@ -1429,11 +1426,8 @@ impl<'a> Parser<'a> { // Just a type path or bound list (trait object type) starting with a trait. // `Type` // `Trait1 + Trait2 + 'a` - if allow_plus && self.eat(&token::BinOp(token::Plus)) { - let poly_trait = PolyTraitRef::new(Vec::new(), path, lo.to(self.prev_span)); - let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)]; - bounds.append(&mut self.parse_ty_param_bounds()?); - TyKind::TraitObject(bounds) + if allow_plus && self.check(&token::BinOp(token::Plus)) { + self.parse_remaining_bounds(Vec::new(), path, lo, true)? } else { TyKind::Path(None, path) } @@ -1451,12 +1445,8 @@ impl<'a> Parser<'a> { self.parse_ty_bare_fn(lifetime_defs)? } else { let path = self.parse_path(PathStyle::Type)?; - let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); - let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)]; - if allow_plus && self.eat(&token::BinOp(token::Plus)) { - bounds.append(&mut self.parse_ty_param_bounds()?) - } - TyKind::TraitObject(bounds) + let parse_plus = allow_plus && self.check(&token::BinOp(token::Plus)); + self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)? } } else if self.eat_keyword(keywords::Impl) { // FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511). @@ -1479,6 +1469,17 @@ impl<'a> Parser<'a> { Ok(P(ty)) } + fn parse_remaining_bounds(&mut self, lifetime_defs: Vec, path: ast::Path, + lo: Span, parse_plus: bool) -> PResult<'a, TyKind> { + let poly_trait_ref = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); + let mut bounds = vec![TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)]; + if parse_plus { + self.bump(); // `+` + bounds.append(&mut self.parse_ty_param_bounds()?); + } + Ok(TyKind::TraitObject(bounds)) + } + fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> { // Do not add `+` to expected tokens. if !allow_plus || self.token != token::BinOp(token::Plus) { -- cgit 1.4.1-3-g733a5 From 116e9831a57dd09b4c580c2f480064299137b0b0 Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Fri, 18 Nov 2016 17:14:42 +0100 Subject: support `default impl` for specialization this commit implements the first step of the `default impl` feature: all items in a `default impl` are (implicitly) `default` and hence specializable. In order to test this feature I've copied all the tests provided for the `default` method implementation (in run-pass/specialization and compile-fail/specialization directories) and moved the `default` keyword from the item to the impl. See referenced issue for further info --- cargo | 2 +- rls | 2 +- src/compiler-rt | 2 +- src/doc/book | 2 +- src/doc/reference | 2 +- src/jemalloc | 2 +- src/liblibc | 2 +- src/librustc/hir/lowering.rs | 9 +- src/librustc/hir/mod.rs | 1 + src/librustc/hir/print.rs | 15 ++- src/librustc/middle/reachable.rs | 4 +- src/librustc/middle/resolve_lifetime.rs | 4 +- src/librustc/traits/project.rs | 24 ++++- src/librustc_metadata/cstore_impl.rs | 1 + src/librustc_metadata/decoder.rs | 4 + src/librustc_metadata/encoder.rs | 4 +- src/librustc_metadata/schema.rs | 1 + src/librustc_save_analysis/dump_visitor.rs | 4 +- src/librustc_trans/collector.rs | 3 +- src/librustc_typeck/check/mod.rs | 18 +++- src/librustc_typeck/check/wfcheck.rs | 4 +- src/librustc_typeck/coherence/unsafety.rs | 2 +- src/librustdoc/doctree.rs | 1 + src/librustdoc/visit_ast.rs | 3 +- src/libsyntax/ast.rs | 1 + src/libsyntax/feature_gate.rs | 11 ++- src/libsyntax/fold.rs | 9 +- src/libsyntax/parse/parser.rs | 29 ++++-- src/libsyntax/print/pprust.rs | 13 ++- src/libsyntax/visit.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 1 + src/rt/hoedown | 1 - .../specialization-default-projection.rs | 46 +++++++++ .../defaultimpl/specialization-default-types.rs | 45 +++++++++ .../specialization-feature-gate-default.rs | 21 ++++ .../defaultimpl/specialization-no-default.rs | 95 ++++++++++++++++++ .../defaultimpl/auxiliary/go_trait.rs | 53 +++++++++++ .../auxiliary/specialization_cross_crate.rs | 82 ++++++++++++++++ .../specialization_cross_crate_defaults.rs | 49 ++++++++++ .../specialization-allowed-cross-crate.rs | 31 ++++++ .../defaultimpl/specialization-assoc-fns.rs | 37 +++++++ .../defaultimpl/specialization-basics.rs | 106 +++++++++++++++++++++ .../specialization-cross-crate-defaults.rs | 49 ++++++++++ .../specialization-cross-crate-no-gate.rs | 29 ++++++ .../defaultimpl/specialization-cross-crate.rs | 58 +++++++++++ .../defaultimpl/specialization-default-methods.rs | 94 ++++++++++++++++++ .../defaultimpl/specialization-out-of-order.rs | 27 ++++++ .../specialization-overlap-projection.rs | 33 +++++++ .../defaultimpl/specialization-projection-alias.rs | 32 +++++++ .../defaultimpl/specialization-projection.rs | 49 ++++++++++ 50 files changed, 1078 insertions(+), 41 deletions(-) delete mode 160000 src/rt/hoedown create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-feature-gate-default.rs create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-no-default.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/auxiliary/go_trait.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-basics.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-projection.rs (limited to 'src/libsyntax/parse') diff --git a/cargo b/cargo index 8326a3683a9..c416fb60b11 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit 8326a3683a9045d825e4fdc4021af340ee3b3755 +Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28 diff --git a/rls b/rls index 6ecff95fdc3..016cbc514cf 160000 --- a/rls +++ b/rls @@ -1 +1 @@ -Subproject commit 6ecff95fdc3ee7ceed2b9b0cc1a3a64876860bce +Subproject commit 016cbc514cf44a2bd3fe806e8afa6b9c50287373 diff --git a/src/compiler-rt b/src/compiler-rt index d30da544a8a..a8fc4c169fa 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit d30da544a8afc5d78391dee270bdf40e74a215d3 +Subproject commit a8fc4c169fac43a5dc204d4fd56ddb1739f8c178 diff --git a/src/doc/book b/src/doc/book index ad7de198561..beea82b9230 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit ad7de198561b3a12217ea2da76d796d9c7fc0ed3 +Subproject commit beea82b9230cd641dd1ca263cf31025ace4aebb5 diff --git a/src/doc/reference b/src/doc/reference index 6b0de90d87d..b060f732145 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 6b0de90d87dda15e323ef24cdf7ed873ac5cf4d3 +Subproject commit b060f732145f2fa16df84c74e511df08a3a47c5d diff --git a/src/jemalloc b/src/jemalloc index 11bfb0dcf85..e058ca66169 160000 --- a/src/jemalloc +++ b/src/jemalloc @@ -1 +1 @@ -Subproject commit 11bfb0dcf85f7aa92abd30524bb1e42e18d108c6 +Subproject commit e058ca661692a8d01f8cf9d35939dfe3105ce968 diff --git a/src/liblibc b/src/liblibc index c34a802d1eb..05a2d197356 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit c34a802d1eb037b44c5252078c7270b5472e0f65 +Subproject commit 05a2d197356ef253dfd985166576619ac9b6947f diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index b7aafa0a9ab..5fb8170cd6c 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1326,7 +1326,13 @@ impl<'a> LoweringContext<'a> { hir::ItemDefaultImpl(self.lower_unsafety(unsafety), trait_ref) } - ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => { + ItemKind::Impl(unsafety, + polarity, + defaultness, + ref generics, + ref ifce, + ref ty, + ref impl_items) => { let new_impl_items = impl_items.iter() .map(|item| self.lower_impl_item_ref(item)) .collect(); @@ -1340,6 +1346,7 @@ impl<'a> LoweringContext<'a> { hir::ItemImpl(self.lower_unsafety(unsafety), self.lower_impl_polarity(polarity), + self.lower_defaultness(defaultness), self.lower_generics(generics), ifce, self.lower_ty(ty), diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 562b5884440..cb7f530b995 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1712,6 +1712,7 @@ pub enum Item_ { /// An implementation, eg `impl Trait for Foo { .. }` ItemImpl(Unsafety, ImplPolarity, + Defaultness, Generics, Option, // (optional) trait this impl implements P, // self diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 5144f75b1a3..dec0753be06 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -678,12 +678,14 @@ impl<'a> State<'a> { } hir::ItemImpl(unsafety, polarity, + defaultness, ref generics, ref opt_trait, ref ty, ref impl_items) => { self.head("")?; self.print_visibility(&item.vis)?; + self.print_defaultness(defaultness)?; self.print_unsafety(unsafety)?; self.word_nbsp("impl")?; @@ -820,6 +822,13 @@ impl<'a> State<'a> { } } + pub fn print_defaultness(&mut self, defaultness: hir::Defaultness) -> io::Result<()> { + if let hir::Defaultness::Default = defaultness { + self.word_nbsp("default")?; + } + Ok(()) + } + pub fn print_struct(&mut self, struct_def: &hir::VariantData, generics: &hir::Generics, @@ -931,11 +940,7 @@ impl<'a> State<'a> { self.hardbreak_if_not_bol()?; self.maybe_print_comment(ii.span.lo)?; self.print_outer_attributes(&ii.attrs)?; - - match ii.defaultness { - hir::Defaultness::Default { .. } => self.word_nbsp("default")?, - hir::Defaultness::Final => (), - } + self.print_defaultness(ii.defaultness)?; match ii.node { hir::ImplItemKind::Const(ref ty, expr) => { diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index be4ec16cd63..12280acfac2 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -50,7 +50,7 @@ fn item_might_be_inlined(item: &hir::Item) -> bool { } match item.node { - hir::ItemImpl(_, _, ref generics, ..) | + hir::ItemImpl(_, _, _, ref generics, ..) | hir::ItemFn(.., ref generics, _) => { generics_require_inlining(generics) } @@ -186,7 +186,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // does too. let impl_node_id = self.tcx.hir.as_local_node_id(impl_did).unwrap(); match self.tcx.hir.expect_item(impl_node_id).node { - hir::ItemImpl(_, _, ref generics, ..) => { + hir::ItemImpl(_, _, _, ref generics, ..) => { generics_require_inlining(generics) } _ => false diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index a1aabc775a3..a8ba708cc2c 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -331,7 +331,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir::ItemStruct(_, ref generics) | hir::ItemUnion(_, ref generics) | hir::ItemTrait(_, ref generics, ..) | - hir::ItemImpl(_, _, ref generics, ..) => { + hir::ItemImpl(_, _, _, ref generics, ..) => { // These kinds of items have only early bound lifetime parameters. let mut index = if let hir::ItemTrait(..) = item.node { 1 // Self comes before lifetimes @@ -834,7 +834,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } match parent.node { hir::ItemTrait(_, ref generics, ..) | - hir::ItemImpl(_, _, ref generics, ..) => { + hir::ItemImpl(_, _, _, ref generics, ..) => { index += (generics.lifetimes.len() + generics.ty_params.len()) as u32; } _ => {} diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 3d8f9e41c67..f417ad5b3d9 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -33,6 +33,7 @@ use ty::subst::Subst; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; use util::common::FN_OUTPUT_NAME; +use hir::{self}; /// Depending on the stage of compilation, we want projection to be /// more or less conservative. @@ -923,7 +924,28 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // being invoked). node_item.item.defaultness.has_value() } else { - node_item.item.defaultness.is_default() + let is_default = match selcx.tcx() + .map + .as_local_node_id(node_item.node.def_id()) { + Some(node_id) => { + let item = selcx.tcx().map.expect_item(node_id); + if let hir::ItemImpl(_, _, defaultness, ..) = item.node { + defaultness.is_default() + } else { + false + } + } + None => { + selcx.tcx() + .global_tcx() + .sess + .cstore + .impl_defaultness(node_item.node.def_id()) + .is_default() + } + }; + + node_item.item.defaultness.is_default() || is_default }; // Only reveal a specializable default if we're past type-checking diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 9e6a45e7f8b..618c1711dad 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -90,6 +90,7 @@ provide! { <'tcx> tcx, def_id, cdata associated_item => { cdata.get_associated_item(def_id.index) } impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) } impl_polarity => { cdata.get_impl_polarity(def_id.index) } + impl_defaultness => { cdata.get_impl_defaultness(def_id.index) } coerce_unsized_info => { cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| { bug!("coerce_unsized_info: `{:?}` is missing its info", def_id); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index a9eae5281b2..ff643c17cfa 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -629,6 +629,10 @@ impl<'a, 'tcx> CrateMetadata { self.get_impl_data(id).polarity } + pub fn get_impl_defaultness(&self, id: DefIndex) -> hir::Defaultness { + self.get_impl_data(id).defaultness + } + pub fn get_coerce_unsized_info(&self, id: DefIndex) -> Option { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index ce9f0a73fe2..d55f489107d 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -706,6 +706,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { hir::ItemDefaultImpl(..) => { let data = ImplData { polarity: hir::ImplPolarity::Positive, + defaultness: hir::Defaultness::Final, parent_impl: None, coerce_unsized_info: None, trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref)), @@ -713,7 +714,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { EntryKind::DefaultImpl(self.lazy(&data)) } - hir::ItemImpl(_, polarity, ..) => { + hir::ItemImpl(_, polarity, defaultness, ..) => { let trait_ref = tcx.impl_trait_ref(def_id); let parent = if let Some(trait_ref) = trait_ref { let trait_def = tcx.lookup_trait_def(trait_ref.def_id); @@ -740,6 +741,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, 'tcx> { let data = ImplData { polarity: polarity, + defaultness: defaultness, parent_impl: parent, coerce_unsized_info: coerce_unsized_info, trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref)), diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 2f2e0e125ae..933c3482474 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -406,6 +406,7 @@ impl_stable_hash_for!(struct TraitData<'tcx> { #[derive(RustcEncodable, RustcDecodable)] pub struct ImplData<'tcx> { pub polarity: hir::ImplPolarity, + pub defaultness: hir::Defaultness, pub parent_impl: Option, /// This is `Some` only for impls of `CoerceUnsized`. diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 3e8f7e11b6b..36e59b4774a 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -429,8 +429,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } None => { - if let Some(NodeItem(item)) = self.tcx.hir.get_if_local(id) { - if let hir::ItemImpl(_, _, _, _, ref ty, _) = item.node { + if let Some(NodeItem(item)) = self.tcx.map.get_if_local(id) { + if let hir::ItemImpl(_, _, _, _, _, ref ty, _) = item.node { trait_id = self.lookup_def_id(ty.id); } } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 13bb0d37125..991470ebe64 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -880,7 +880,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { let parent_node_id = hir_map.get_parent_node(ii.id); let is_impl_generic = match hir_map.expect_item(parent_node_id) { &hir::Item { - node: hir::ItemImpl(_, _, ref generics, ..), + node: hir::ItemImpl(_, _, _, ref generics, ..), .. } => { generics.is_type_parameterized() @@ -911,6 +911,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' let tcx = scx.tcx(); match item.node { hir::ItemImpl(_, + _, _, ref generics, .., diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 098e8c53a52..74886e503a8 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1142,7 +1142,23 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let Some(parent) = parent { if parent.item.is_final() { - report_forbidden_specialization(tcx, impl_item, parent.node.def_id()); + let is_final = match tcx.map.as_local_node_id(parent.node.def_id()) { + Some(node_id) => { + let item = tcx.map.expect_item(node_id); + if let hir::ItemImpl(_, _, defaultness, ..) = item.node { + defaultness.is_final() + } else { + true + } + } + None => { + tcx.global_tcx().sess.cstore.impl_defaultness(parent.node.def_id()).is_final() + } + }; + + if is_final { + report_forbidden_specialization(tcx, impl_item, parent.node.def_id()); + } } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 85c87adf9be..8b8a765dd60 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -105,11 +105,11 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { /// /// won't be allowed unless there's an *explicit* implementation of `Send` /// for `T` - hir::ItemImpl(_, hir::ImplPolarity::Positive, _, + hir::ItemImpl(_, hir::ImplPolarity::Positive, _, _, ref trait_ref, ref self_ty, _) => { self.check_impl(item, self_ty, trait_ref); } - hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), ..) => { + hir::ItemImpl(_, hir::ImplPolarity::Negative, _, _, Some(_), ..) => { // FIXME(#27579) what amount of WF checking do we need for neg impls? let trait_ref = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id)).unwrap(); diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index 22247d2531a..323700f9eaf 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -87,7 +87,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> { hir::ItemDefaultImpl(unsafety, _) => { self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive); } - hir::ItemImpl(unsafety, polarity, ref generics, Some(_), _, _) => { + hir::ItemImpl(unsafety, polarity, _, ref generics, ..) => { self.check_unsafety_coherence(item, Some(generics), unsafety, polarity); } _ => {} diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index d819268240b..71594825cdb 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -214,6 +214,7 @@ pub struct Trait { pub struct Impl { pub unsafety: hir::Unsafety, pub polarity: hir::ImplPolarity, + pub defaultness: hir::Defaultness, pub generics: hir::Generics, pub trait_: Option, pub for_: P, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 4252f2981ed..4ffc8c97c50 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -502,7 +502,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { om.traits.push(t); }, - hir::ItemImpl(unsafety, polarity, ref gen, ref tr, ref ty, ref item_ids) => { + hir::ItemImpl(unsafety, polarity, defaultness, ref gen, ref tr, ref ty, ref item_ids) => { // Don't duplicate impls when inlining, we'll pick them up // regardless of where they're located. if !self.inlining { @@ -512,6 +512,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let i = Impl { unsafety: unsafety, polarity: polarity, + defaultness: defaultness, generics: gen.clone(), trait_: tr.clone(), for_: ty.clone(), diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 131adfe47af..e5bb02fe082 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1852,6 +1852,7 @@ pub enum ItemKind { /// E.g. `impl Foo { .. }` or `impl Trait for Foo { .. }` Impl(Unsafety, ImplPolarity, + Defaultness, Generics, Option, // (optional) trait this impl implements P, // self diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9b55a860b35..152a4e7ee1a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1215,7 +1215,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { and possibly buggy"); } - ast::ItemKind::Impl(_, polarity, _, _, _, _) => { + ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => { match polarity { ast::ImplPolarity::Negative => { gate_feature_post!(&self, optin_builtin_traits, @@ -1225,6 +1225,15 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { }, _ => {} } + + match defaultness { + ast::Defaultness::Default => { + gate_feature_post!(&self, specialization, + i.span, + "specialization is unstable"); + } + _ => {} + } } _ => {} diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index f39399a62e8..58cf50cdc00 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -897,9 +897,16 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { ItemKind::DefaultImpl(unsafety, ref trait_ref) => { ItemKind::DefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone())) } - ItemKind::Impl(unsafety, polarity, generics, ifce, ty, impl_items) => ItemKind::Impl( + ItemKind::Impl(unsafety, + polarity, + defaultness, + generics, + ifce, + ty, + impl_items) => ItemKind::Impl( unsafety, polarity, + defaultness, folder.fold_generics(generics), ifce.map(|trait_ref| folder.fold_trait_ref(trait_ref.clone())), folder.fold_ty(ty), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 1baf0d1b54c..58f81c8b3d7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4863,7 +4863,9 @@ impl<'a> Parser<'a> { /// impl Foo { ... } /// impl ToString for &'static T { ... } /// impl Send for .. {} - fn parse_item_impl(&mut self, unsafety: ast::Unsafety) -> PResult<'a, ItemInfo> { + fn parse_item_impl(&mut self, + unsafety: ast::Unsafety, + defaultness: Defaultness) -> PResult<'a, ItemInfo> { let impl_span = self.span; // First, parse type parameters if necessary. @@ -4944,7 +4946,7 @@ impl<'a> Parser<'a> { } Ok((keywords::Invalid.ident(), - ItemKind::Impl(unsafety, polarity, generics, opt_trait, ty, impl_items), + ItemKind::Impl(unsafety, polarity, defaultness, generics, opt_trait, ty, impl_items), Some(attrs))) } } @@ -5756,13 +5758,19 @@ impl<'a> Parser<'a> { maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } - if self.check_keyword(keywords::Unsafe) && - self.look_ahead(1, |t| t.is_keyword(keywords::Impl)) + if (self.check_keyword(keywords::Unsafe) && + self.look_ahead(1, |t| t.is_keyword(keywords::Impl))) || + (self.check_keyword(keywords::Default) && + self.look_ahead(1, |t| t.is_keyword(keywords::Unsafe)) && + self.look_ahead(2, |t| t.is_keyword(keywords::Impl))) { // IMPL ITEM + let defaultness = self.parse_defaultness()?; self.expect_keyword(keywords::Unsafe)?; self.expect_keyword(keywords::Impl)?; - let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe)?; + let (ident, + item_, + extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe, defaultness)?; let prev_span = self.prev_span; let item = self.mk_item(lo.to(prev_span), ident, @@ -5856,9 +5864,16 @@ impl<'a> Parser<'a> { maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } - if self.eat_keyword(keywords::Impl) { + if (self.check_keyword(keywords::Impl)) || + (self.check_keyword(keywords::Default) && + self.look_ahead(1, |t| t.is_keyword(keywords::Impl))) + { // IMPL ITEM - let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal)?; + let defaultness = self.parse_defaultness()?; + self.expect_keyword(keywords::Impl)?; + let (ident, + item_, + extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal, defaultness)?; let prev_span = self.prev_span; let item = self.mk_item(lo.to(prev_span), ident, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index be1d26f8fe4..a911c21ed98 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1317,12 +1317,14 @@ impl<'a> State<'a> { } ast::ItemKind::Impl(unsafety, polarity, + defaultness, ref generics, ref opt_trait, ref ty, ref impl_items) => { self.head("")?; self.print_visibility(&item.vis)?; + self.print_defaultness(defaultness)?; self.print_unsafety(unsafety)?; self.word_nbsp("impl")?; @@ -1477,6 +1479,13 @@ impl<'a> State<'a> { } } + pub fn print_defaultness(&mut self, defatulness: ast::Defaultness) -> io::Result<()> { + if let ast::Defaultness::Default = defatulness { + try!(self.word_nbsp("default")); + } + Ok(()) + } + pub fn print_struct(&mut self, struct_def: &ast::VariantData, generics: &ast::Generics, @@ -1602,9 +1611,7 @@ impl<'a> State<'a> { self.hardbreak_if_not_bol()?; self.maybe_print_comment(ii.span.lo)?; self.print_outer_attributes(&ii.attrs)?; - if let ast::Defaultness::Default = ii.defaultness { - self.word_nbsp("default")?; - } + self.print_defaultness(ii.defaultness)?; match ii.node { ast::ImplItemKind::Const(ref ty, ref expr) => { self.print_associated_const(ii.ident, &ty, Some(&expr), &ii.vis)?; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index bae1c56db00..2e42c6986e6 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -266,7 +266,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { ItemKind::DefaultImpl(_, ref trait_ref) => { visitor.visit_trait_ref(trait_ref) } - ItemKind::Impl(_, _, + ItemKind::Impl(_, _, _, ref type_parameters, ref opt_trait_reference, ref typ, diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index e96883c26f3..be7883cad5f 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -658,6 +658,7 @@ impl<'a> TraitDef<'a> { a, ast::ItemKind::Impl(unsafety, ast::ImplPolarity::Positive, + ast::Defaultness::Final, trait_generics, opt_trait_ref, self_type, diff --git a/src/rt/hoedown b/src/rt/hoedown deleted file mode 160000 index da282f1bb72..00000000000 --- a/src/rt/hoedown +++ /dev/null @@ -1 +0,0 @@ -Subproject commit da282f1bb7277b4d30fa1599ee29ad8eb4dd2a92 diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs new file mode 100644 index 00000000000..ad55f44255b --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-default-projection.rs @@ -0,0 +1,46 @@ +// 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. + +#![feature(specialization)] + +// Make sure we can't project defaulted associated types + +trait Foo { + type Assoc; +} + +default impl Foo for T { + type Assoc = (); +} + +impl Foo for u8 { + type Assoc = String; +} + +fn generic() -> ::Assoc { + // `T` could be some downstream crate type that specializes (or, + // for that matter, `u8`). + + () //~ ERROR mismatched types +} + +fn monomorphic() -> () { + // Even though we know that `()` is not specialized in a + // downstream crate, typeck refuses to project here. + + generic::<()>() //~ ERROR mismatched types +} + +fn main() { + // No error here, we CAN project from `u8`, as there is no `default` + // in that impl. + let s: String = generic::(); + println!("{}", s); // bad news if this all compiles +} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs new file mode 100644 index 00000000000..7353f7ac8c5 --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-default-types.rs @@ -0,0 +1,45 @@ +// 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. + +// It should not be possible to use the concrete value of a defaulted +// associated type in the impl defining it -- otherwise, what happens +// if it's overridden? + +#![feature(specialization)] + +trait Example { + type Output; + fn generate(self) -> Self::Output; +} + +default impl Example for T { + type Output = Box; + fn generate(self) -> Self::Output { + Box::new(self) //~ ERROR mismatched types + } +} + +impl Example for bool { + type Output = bool; + fn generate(self) -> bool { self } +} + +fn trouble(t: T) -> Box { + Example::generate(t) //~ ERROR mismatched types +} + +fn weaponize() -> bool { + let b: Box = trouble(true); + *b +} + +fn main() { + weaponize(); +} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-feature-gate-default.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-feature-gate-default.rs new file mode 100644 index 00000000000..5bab4c5438e --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-feature-gate-default.rs @@ -0,0 +1,21 @@ +// 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 specialization must be ungated to use the `default` keyword + +trait Foo { + fn foo(&self); +} + +default impl Foo for T { //~ ERROR specialization is unstable + fn foo(&self) {} +} + +fn main() {} diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-no-default.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-no-default.rs new file mode 100644 index 00000000000..2874108157d --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-no-default.rs @@ -0,0 +1,95 @@ +// 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. + +#![feature(specialization)] + +// Check a number of scenarios in which one impl tries to override another, +// without correctly using `default`. + +//////////////////////////////////////////////////////////////////////////////// +// Test 1: one layer of specialization, multiple methods, missing `default` +//////////////////////////////////////////////////////////////////////////////// + +trait Foo { + fn foo(&self); + fn bar(&self); +} + +impl Foo for T { + fn foo(&self) {} + fn bar(&self) {} +} + +impl Foo for u8 {} +impl Foo for u16 { + fn foo(&self) {} //~ ERROR E0520 +} +impl Foo for u32 { + fn bar(&self) {} //~ ERROR E0520 +} + +//////////////////////////////////////////////////////////////////////////////// +// Test 2: one layer of specialization, missing `default` on associated type +//////////////////////////////////////////////////////////////////////////////// + +trait Bar { + type T; +} + +impl Bar for T { + type T = u8; +} + +impl Bar for u8 { + type T = (); //~ ERROR E0520 +} + +//////////////////////////////////////////////////////////////////////////////// +// Test 3a: multiple layers of specialization, missing interior `default` +//////////////////////////////////////////////////////////////////////////////// + +trait Baz { + fn baz(&self); +} + +default impl Baz for T { + fn baz(&self) {} +} + +impl Baz for T { + fn baz(&self) {} +} + +impl Baz for i32 { + fn baz(&self) {} //~ ERROR E0520 +} + +//////////////////////////////////////////////////////////////////////////////// +// Test 3b: multiple layers of specialization, missing interior `default`, +// redundant `default` in bottom layer. +//////////////////////////////////////////////////////////////////////////////// + +trait Redundant { + fn redundant(&self); +} + +default impl Redundant for T { + fn redundant(&self) {} +} + +impl Redundant for T { + fn redundant(&self) {} +} + +default impl Redundant for i32 { + fn redundant(&self) {} //~ ERROR E0520 +} + +fn main() {} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/go_trait.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/go_trait.rs new file mode 100644 index 00000000000..dd060f8ef40 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/auxiliary/go_trait.rs @@ -0,0 +1,53 @@ +// Copyright 2014 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(specialization)] + +// Common code used for tests that model the Fn/FnMut/FnOnce hierarchy. + +pub trait Go { + fn go(&self, arg: isize); +} + +pub fn go(this: &G, arg: isize) { + this.go(arg) +} + +pub trait GoMut { + fn go_mut(&mut self, arg: isize); +} + +pub fn go_mut(this: &mut G, arg: isize) { + this.go_mut(arg) +} + +pub trait GoOnce { + fn go_once(self, arg: isize); +} + +pub fn go_once(this: G, arg: isize) { + this.go_once(arg) +} + +default impl GoMut for G + where G : Go +{ + fn go_mut(&mut self, arg: isize) { + go(&*self, arg) + } +} + +default impl GoOnce for G + where G : GoMut +{ + fn go_once(mut self, arg: isize) { + go_mut(&mut self, arg) + } +} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs new file mode 100644 index 00000000000..71dd7c99009 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate.rs @@ -0,0 +1,82 @@ +// 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. + +#![feature(specialization)] + +pub trait Foo { + fn foo(&self) -> &'static str; +} + +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic" + } +} + +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone" + } +} + +default impl Foo for (T, U) where T: Clone, U: Clone { + fn foo(&self) -> &'static str { + "generic pair" + } +} + +default impl Foo for (T, T) { + fn foo(&self) -> &'static str { + "generic uniform pair" + } +} + +default impl Foo for (u8, u32) { + fn foo(&self) -> &'static str { + "(u8, u32)" + } +} + +default impl Foo for (u8, u8) { + fn foo(&self) -> &'static str { + "(u8, u8)" + } +} + +default impl Foo for Vec { + fn foo(&self) -> &'static str { + "generic Vec" + } +} + +impl Foo for Vec { + fn foo(&self) -> &'static str { + "Vec" + } +} + +impl Foo for String { + fn foo(&self) -> &'static str { + "String" + } +} + +impl Foo for i32 { + fn foo(&self) -> &'static str { + "i32" + } +} + +pub trait MyMarker {} +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone + MyMarker" + } +} diff --git a/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs b/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs new file mode 100644 index 00000000000..9d0ea64fed4 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/auxiliary/specialization_cross_crate_defaults.rs @@ -0,0 +1,49 @@ +// 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. + + +#![feature(specialization)] + +// First, test only use of explicit `default` items: + +pub trait Foo { + fn foo(&self) -> bool; +} + +default impl Foo for T { + fn foo(&self) -> bool { false } +} + +impl Foo for i32 {} + +impl Foo for i64 { + fn foo(&self) -> bool { true } +} + +// Next, test mixture of explicit `default` and provided methods: + +pub trait Bar { + fn bar(&self) -> i32 { 0 } +} + +impl Bar for T {} // use the provided method + +impl Bar for i32 { + fn bar(&self) -> i32 { 1 } +} +impl<'a> Bar for &'a str {} + +default impl Bar for Vec { + fn bar(&self) -> i32 { 2 } +} +impl Bar for Vec {} +impl Bar for Vec { + fn bar(&self) -> i32 { 3 } +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs b/src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs new file mode 100644 index 00000000000..6b999f38358 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-allowed-cross-crate.rs @@ -0,0 +1,31 @@ +// Copyright 2014 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:go_trait.rs + +#![feature(specialization)] + +extern crate go_trait; + +use go_trait::{Go,GoMut}; +use std::fmt::Debug; +use std::default::Default; + +struct MyThingy; + +impl Go for MyThingy { + fn go(&self, arg: isize) { } +} + +impl GoMut for MyThingy { + fn go_mut(&mut self, arg: isize) { } +} + +fn main() { } diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.rs b/src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.rs new file mode 100644 index 00000000000..b99ba3d0f1c --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-assoc-fns.rs @@ -0,0 +1,37 @@ +// 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. + +// Test that non-method associated functions can be specialized + +#![feature(specialization)] + +trait Foo { + fn mk() -> Self; +} + +default impl Foo for T { + fn mk() -> T { + T::default() + } +} + +impl Foo for Vec { + fn mk() -> Vec { + vec![0] + } +} + +fn main() { + let v1: Vec = Foo::mk(); + let v2: Vec = Foo::mk(); + + assert!(v1.len() == 0); + assert!(v2.len() == 1); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-basics.rs b/src/test/run-pass/specialization/defaultimpl/specialization-basics.rs new file mode 100644 index 00000000000..594f1e4fcdf --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-basics.rs @@ -0,0 +1,106 @@ +// Copyright 2014 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(specialization)] + +// Tests a variety of basic specialization scenarios and method +// dispatch for them. + +trait Foo { + fn foo(&self) -> &'static str; +} + +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic" + } +} + +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone" + } +} + +default impl Foo for (T, U) where T: Clone, U: Clone { + fn foo(&self) -> &'static str { + "generic pair" + } +} + +default impl Foo for (T, T) { + fn foo(&self) -> &'static str { + "generic uniform pair" + } +} + +default impl Foo for (u8, u32) { + fn foo(&self) -> &'static str { + "(u8, u32)" + } +} + +default impl Foo for (u8, u8) { + fn foo(&self) -> &'static str { + "(u8, u8)" + } +} + +default impl Foo for Vec { + fn foo(&self) -> &'static str { + "generic Vec" + } +} + +impl Foo for Vec { + fn foo(&self) -> &'static str { + "Vec" + } +} + +impl Foo for String { + fn foo(&self) -> &'static str { + "String" + } +} + +impl Foo for i32 { + fn foo(&self) -> &'static str { + "i32" + } +} + +struct NotClone; + +trait MyMarker {} +default impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone + MyMarker" + } +} + +#[derive(Clone)] +struct MarkedAndClone; +impl MyMarker for MarkedAndClone {} + +fn main() { + assert!(NotClone.foo() == "generic"); + assert!(0u8.foo() == "generic Clone"); + assert!(vec![NotClone].foo() == "generic"); + assert!(vec![0u8].foo() == "generic Vec"); + assert!(vec![0i32].foo() == "Vec"); + assert!(0i32.foo() == "i32"); + assert!(String::new().foo() == "String"); + assert!(((), 0).foo() == "generic pair"); + assert!(((), ()).foo() == "generic uniform pair"); + assert!((0u8, 0u32).foo() == "(u8, u32)"); + assert!((0u8, 0u8).foo() == "(u8, u8)"); + assert!(MarkedAndClone.foo() == "generic Clone + MyMarker"); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs new file mode 100644 index 00000000000..62c7e3e2e44 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-defaults.rs @@ -0,0 +1,49 @@ +// 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. + +// aux-build:specialization_cross_crate_defaults.rs + +#![feature(specialization)] + +extern crate specialization_cross_crate_defaults; + +use specialization_cross_crate_defaults::*; + +struct LocalDefault; +struct LocalOverride; + +impl Foo for LocalDefault {} + +impl Foo for LocalOverride { + fn foo(&self) -> bool { true } +} + +fn test_foo() { + assert!(!0i8.foo()); + assert!(!0i32.foo()); + assert!(0i64.foo()); + + assert!(!LocalDefault.foo()); + assert!(LocalOverride.foo()); +} + +fn test_bar() { + assert!(0u8.bar() == 0); + assert!(0i32.bar() == 1); + assert!("hello".bar() == 0); + assert!(vec![()].bar() == 2); + assert!(vec![0i32].bar() == 2); + assert!(vec![0i64].bar() == 3); +} + +fn main() { + test_foo(); + test_bar(); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs new file mode 100644 index 00000000000..b9548539e16 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate-no-gate.rs @@ -0,0 +1,29 @@ +// 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. + +// Test that specialization works even if only the upstream crate enables it + +// aux-build:specialization_cross_crate.rs + +extern crate specialization_cross_crate; + +use specialization_cross_crate::*; + +fn main() { + assert!(0u8.foo() == "generic Clone"); + assert!(vec![0u8].foo() == "generic Vec"); + assert!(vec![0i32].foo() == "Vec"); + assert!(0i32.foo() == "i32"); + assert!(String::new().foo() == "String"); + assert!(((), 0).foo() == "generic pair"); + assert!(((), ()).foo() == "generic uniform pair"); + assert!((0u8, 0u32).foo() == "(u8, u32)"); + assert!((0u8, 0u8).foo() == "(u8, u8)"); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs new file mode 100644 index 00000000000..7517824b62b --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-cross-crate.rs @@ -0,0 +1,58 @@ +// 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. + +// aux-build:specialization_cross_crate.rs + +#![feature(specialization)] + +extern crate specialization_cross_crate; + +use specialization_cross_crate::*; + +struct NotClone; + +#[derive(Clone)] +struct MarkedAndClone; +impl MyMarker for MarkedAndClone {} + +struct MyType(T); +default impl Foo for MyType { + fn foo(&self) -> &'static str { + "generic MyType" + } +} + +impl Foo for MyType { + fn foo(&self) -> &'static str { + "MyType" + } +} + +struct MyOtherType; +impl Foo for MyOtherType {} + +fn main() { + assert!(NotClone.foo() == "generic"); + assert!(0u8.foo() == "generic Clone"); + assert!(vec![NotClone].foo() == "generic"); + assert!(vec![0u8].foo() == "generic Vec"); + assert!(vec![0i32].foo() == "Vec"); + assert!(0i32.foo() == "i32"); + assert!(String::new().foo() == "String"); + assert!(((), 0).foo() == "generic pair"); + assert!(((), ()).foo() == "generic uniform pair"); + assert!((0u8, 0u32).foo() == "(u8, u32)"); + assert!((0u8, 0u8).foo() == "(u8, u8)"); + assert!(MarkedAndClone.foo() == "generic Clone + MyMarker"); + + assert!(MyType(()).foo() == "generic MyType"); + assert!(MyType(0u8).foo() == "MyType"); + assert!(MyOtherType.foo() == "generic"); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs b/src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs new file mode 100644 index 00000000000..4ac9afc1c89 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-default-methods.rs @@ -0,0 +1,94 @@ +// 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. + +#![feature(specialization)] + +// Test that default methods are cascaded correctly + +// First, test only use of explicit `default` items: + +trait Foo { + fn foo(&self) -> bool; +} + +// Specialization tree for Foo: +// +// T +// / \ +// i32 i64 + +default impl Foo for T { + fn foo(&self) -> bool { false } +} + +impl Foo for i32 {} + +impl Foo for i64 { + fn foo(&self) -> bool { true } +} + +fn test_foo() { + assert!(!0i8.foo()); + assert!(!0i32.foo()); + assert!(0i64.foo()); +} + +// Next, test mixture of explicit `default` and provided methods: + +trait Bar { + fn bar(&self) -> i32 { 0 } +} + +// Specialization tree for Bar. +// Uses of $ designate that method is provided +// +// $Bar (the trait) +// | +// T +// /|\ +// / | \ +// / | \ +// / | \ +// / | \ +// / | \ +// $i32 &str $Vec +// /\ +// / \ +// Vec $Vec + +// use the provided method +impl Bar for T {} + +impl Bar for i32 { + fn bar(&self) -> i32 { 1 } +} +impl<'a> Bar for &'a str {} + +default impl Bar for Vec { + fn bar(&self) -> i32 { 2 } +} +impl Bar for Vec {} +impl Bar for Vec { + fn bar(&self) -> i32 { 3 } +} + +fn test_bar() { + assert!(0u8.bar() == 0); + assert!(0i32.bar() == 1); + assert!("hello".bar() == 0); + assert!(vec![()].bar() == 2); + assert!(vec![0i32].bar() == 2); + assert!(vec![0i64].bar() == 3); +} + +fn main() { + test_foo(); + test_bar(); +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs b/src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs new file mode 100644 index 00000000000..f77b88e2f85 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-out-of-order.rs @@ -0,0 +1,27 @@ +// 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. + +// Test that you can list the more specific impl before the more general one. + +#![feature(specialization)] + +trait Foo { + type Out; +} + +impl Foo for bool { + type Out = (); +} + +default impl Foo for T { + type Out = bool; +} + +fn main() {} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs b/src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs new file mode 100644 index 00000000000..500cded38c1 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-overlap-projection.rs @@ -0,0 +1,33 @@ +// 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. + +// Test that impls on projected self types can resolve overlap, even when the +// projections involve specialization, so long as the associated type is +// provided by the most specialized impl. + +#![feature(specialization)] + +trait Assoc { + type Output; +} + +default impl Assoc for T { + type Output = bool; +} + +impl Assoc for u8 { type Output = u8; } +impl Assoc for u16 { type Output = u16; } + +trait Foo {} +impl Foo for u32 {} +impl Foo for ::Output {} +impl Foo for ::Output {} + +fn main() {} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs b/src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs new file mode 100644 index 00000000000..2397c3e2bff --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-projection-alias.rs @@ -0,0 +1,32 @@ +// 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(specialization)] + +// Regression test for ICE when combining specialized associated types and type +// aliases + +trait Id_ { + type Out; +} + +type Id = ::Out; + +default impl Id_ for T { + type Out = T; +} + +fn test_proection() { + let x: Id = panic!(); +} + +fn main() { + +} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-projection.rs b/src/test/run-pass/specialization/defaultimpl/specialization-projection.rs new file mode 100644 index 00000000000..6a833ba6760 --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-projection.rs @@ -0,0 +1,49 @@ +// 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. + +#![feature(specialization)] + +// Make sure we *can* project non-defaulted associated types +// cf compile-fail/specialization-default-projection.rs + +// First, do so without any use of specialization + +trait Foo { + type Assoc; +} + +impl Foo for T { + type Assoc = (); +} + +fn generic_foo() -> ::Assoc { + () +} + +// Next, allow for one layer of specialization + +trait Bar { + type Assoc; +} + +default impl Bar for T { + type Assoc = (); +} + +impl Bar for T { + type Assoc = u8; +} + +fn generic_bar_clone() -> ::Assoc { + 0u8 +} + +fn main() { +} -- cgit 1.4.1-3-g733a5 From e4825290223f39647bf2782b9d4ef5f00554c7ee Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Dec 2016 16:12:38 -0800 Subject: Fix invalid module suggestion --- src/libsyntax/parse/parser.rs | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 1baf0d1b54c..dd32b40554b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5363,26 +5363,33 @@ impl<'a> Parser<'a> { } let mut err = self.diagnostic().struct_span_err(id_sp, "cannot declare a new module at this location"); - let this_module = match self.directory.path.file_name() { - Some(file_name) => file_name.to_str().unwrap().to_owned(), - None => self.root_module_name.as_ref().unwrap().clone(), - }; - err.span_note(id_sp, - &format!("maybe move this module `{0}` to its own directory \ - via `{0}{1}mod.rs`", - this_module, - path::MAIN_SEPARATOR)); + if id_sp != syntax_pos::DUMMY_SP { + let full_path = self.sess.codemap().span_to_filename(id_sp); + let path = Path::new(&full_path); + let filename = path.file_stem().unwrap(); + let parent = path.parent().unwrap_or(Path::new("")) + .to_str().unwrap_or("").to_owned(); + let path = format!("{}/{}", + if parent.len() == 0 { "." } else { &parent }, + filename.to_str().unwrap_or("")); + err.span_note(id_sp, + &format!("maybe move this module `{0}` to its own directory \ + via `{0}{1}mod.rs`", + path, + path::MAIN_SEPARATOR)); + } if paths.path_exists { err.span_note(id_sp, &format!("... or maybe `use` the module `{}` instead \ of possibly redeclaring it", paths.name)); - Err(err) - } else { - Err(err) } + Err(err) } else { - paths.result.map_err(|err| self.span_fatal_err(id_sp, err)) + match paths.result { + Ok(succ) => Ok(succ), + Err(err) => Err(self.span_fatal_err(id_sp, &err.err_msg, &err.help_msg)), + } } } -- cgit 1.4.1-3-g733a5 From bd880bc6bf62a223664467d4df2b056a9122b7e7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 3 Jan 2017 12:19:13 +0100 Subject: Add tests for module suggestions --- src/libsyntax/parse/parser.rs | 43 ++++++++++++++-------- src/test/compile-fail/auxiliary/foo/bar.rs | 11 ++++++ src/test/compile-fail/auxiliary/foo/mod.rs | 11 ++++++ .../compile-fail/invalid-module-declaration.rs | 20 ++++++++++ 4 files changed, 70 insertions(+), 15 deletions(-) create mode 100644 src/test/compile-fail/auxiliary/foo/bar.rs create mode 100644 src/test/compile-fail/auxiliary/foo/mod.rs create mode 100644 src/test/compile-fail/invalid-module-declaration.rs (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index dd32b40554b..ac72d21ec42 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -58,8 +58,11 @@ use symbol::{Symbol, keywords}; use util::ThinVec; use std::collections::HashSet; -use std::{cmp, mem, slice}; -use std::path::{self, Path, PathBuf}; +use std::env; +use std::mem; +use std::path::{Path, PathBuf}; +use std::rc::Rc; +use std::slice; bitflags! { flags Restrictions: u8 { @@ -5364,19 +5367,29 @@ impl<'a> Parser<'a> { let mut err = self.diagnostic().struct_span_err(id_sp, "cannot declare a new module at this location"); if id_sp != syntax_pos::DUMMY_SP { - let full_path = self.sess.codemap().span_to_filename(id_sp); - let path = Path::new(&full_path); - let filename = path.file_stem().unwrap(); - let parent = path.parent().unwrap_or(Path::new("")) - .to_str().unwrap_or("").to_owned(); - let path = format!("{}/{}", - if parent.len() == 0 { "." } else { &parent }, - filename.to_str().unwrap_or("")); - err.span_note(id_sp, - &format!("maybe move this module `{0}` to its own directory \ - via `{0}{1}mod.rs`", - path, - path::MAIN_SEPARATOR)); + let mut src_path = PathBuf::from(self.sess.codemap().span_to_filename(id_sp)); + if let Some(stem) = src_path.clone().file_stem() { + let mut dest_path = src_path.clone(); + dest_path.set_file_name(stem); + dest_path.push("mod.rs"); + if let Ok(cur_dir) = env::current_dir() { + let tmp = if let (Ok(src_path), Ok(dest_path)) = + (Path::new(&src_path).strip_prefix(&cur_dir), + Path::new(&dest_path).strip_prefix(&cur_dir)) { + Some((src_path.to_path_buf(), dest_path.to_path_buf())) + } else { + None + }; + if let Some(tmp) = tmp { + src_path = tmp.0; + dest_path = tmp.1; + } + } + err.span_note(id_sp, + &format!("maybe move this module `{}` to its own \ + directory via `{}`", src_path.to_string_lossy(), + dest_path.to_string_lossy())); + } } if paths.path_exists { err.span_note(id_sp, diff --git a/src/test/compile-fail/auxiliary/foo/bar.rs b/src/test/compile-fail/auxiliary/foo/bar.rs new file mode 100644 index 00000000000..4b6b4f5ebf8 --- /dev/null +++ b/src/test/compile-fail/auxiliary/foo/bar.rs @@ -0,0 +1,11 @@ +// Copyright 2017 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. + +pub mod baz; diff --git a/src/test/compile-fail/auxiliary/foo/mod.rs b/src/test/compile-fail/auxiliary/foo/mod.rs new file mode 100644 index 00000000000..6d77fb60a35 --- /dev/null +++ b/src/test/compile-fail/auxiliary/foo/mod.rs @@ -0,0 +1,11 @@ +// Copyright 2017 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. + +pub mod bar; diff --git a/src/test/compile-fail/invalid-module-declaration.rs b/src/test/compile-fail/invalid-module-declaration.rs new file mode 100644 index 00000000000..658fa0a65c4 --- /dev/null +++ b/src/test/compile-fail/invalid-module-declaration.rs @@ -0,0 +1,20 @@ +// 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. + +// ignore-tidy-linelength + +// error-pattern: cannot declare a new module at this location +// error-pattern: maybe move this module `src/test/compile-fail/auxiliary/foo/bar.rs` to its own directory via `src/test/compile-fail/auxiliary/foo/bar/mod.rs` + +mod auxiliary { + mod foo; +} + +fn main() {} -- cgit 1.4.1-3-g733a5 From b10c04472bf0969d123aa4461a7f0a1a255ac660 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 25 Feb 2017 17:08:46 +0100 Subject: Remove strip prefix --- src/libsyntax/parse/parser.rs | 18 ++---------------- src/test/compile-fail/invalid-module-declaration.rs | 2 +- 2 files changed, 3 insertions(+), 17 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ac72d21ec42..9df791c1c12 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -58,7 +58,6 @@ use symbol::{Symbol, keywords}; use util::ThinVec; use std::collections::HashSet; -use std::env; use std::mem; use std::path::{Path, PathBuf}; use std::rc::Rc; @@ -5367,24 +5366,11 @@ impl<'a> Parser<'a> { let mut err = self.diagnostic().struct_span_err(id_sp, "cannot declare a new module at this location"); if id_sp != syntax_pos::DUMMY_SP { - let mut src_path = PathBuf::from(self.sess.codemap().span_to_filename(id_sp)); + let src_path = PathBuf::from(self.sess.codemap().span_to_filename(id_sp)); if let Some(stem) = src_path.clone().file_stem() { let mut dest_path = src_path.clone(); dest_path.set_file_name(stem); dest_path.push("mod.rs"); - if let Ok(cur_dir) = env::current_dir() { - let tmp = if let (Ok(src_path), Ok(dest_path)) = - (Path::new(&src_path).strip_prefix(&cur_dir), - Path::new(&dest_path).strip_prefix(&cur_dir)) { - Some((src_path.to_path_buf(), dest_path.to_path_buf())) - } else { - None - }; - if let Some(tmp) = tmp { - src_path = tmp.0; - dest_path = tmp.1; - } - } err.span_note(id_sp, &format!("maybe move this module `{}` to its own \ directory via `{}`", src_path.to_string_lossy(), @@ -5401,7 +5387,7 @@ impl<'a> Parser<'a> { } else { match paths.result { Ok(succ) => Ok(succ), - Err(err) => Err(self.span_fatal_err(id_sp, &err.err_msg, &err.help_msg)), + Err(err) => Err(self.span_fatal_err(id_sp, err)), } } } diff --git a/src/test/compile-fail/invalid-module-declaration.rs b/src/test/compile-fail/invalid-module-declaration.rs index 658fa0a65c4..c15cfb8cc8e 100644 --- a/src/test/compile-fail/invalid-module-declaration.rs +++ b/src/test/compile-fail/invalid-module-declaration.rs @@ -11,7 +11,7 @@ // ignore-tidy-linelength // error-pattern: cannot declare a new module at this location -// error-pattern: maybe move this module `src/test/compile-fail/auxiliary/foo/bar.rs` to its own directory via `src/test/compile-fail/auxiliary/foo/bar/mod.rs` +// error-pattern: maybe move this module mod auxiliary { mod foo; -- cgit 1.4.1-3-g733a5 From 715811d0be05dcdc55b44f97d9fd2cd1eb7eee05 Mon Sep 17 00:00:00 2001 From: Gianni Ciccarelli Date: Mon, 24 Apr 2017 09:56:54 +0000 Subject: support `default impl` for specialization pr review --- cargo | 2 +- rls | 2 +- src/compiler-rt | 2 +- src/doc/book | 2 +- src/doc/reference | 2 +- src/grammar/parser-lalr.y | 28 +++--- src/jemalloc | 2 +- src/liblibc | 2 +- src/librustc/hir/lowering.rs | 3 + src/librustc/ich/impls_hir.rs | 2 +- src/librustc/middle/cstore.rs | 2 + src/librustc/traits/project.rs | 25 +---- src/librustc/traits/util.rs | 21 ++++ src/librustc_metadata/cstore_impl.rs | 7 +- src/librustc_metadata/schema.rs | 1 + src/librustc_save_analysis/dump_visitor.rs | 2 +- src/librustc_typeck/check/mod.rs | 16 +--- src/librustc_typeck/collect.rs | 6 +- src/libsyntax/parse/parser.rs | 14 ++- src/rt/hoedown | 1 + ...cialization-no-default-trait-implementations.rs | 19 ++++ .../defaultimpl/specialization-basics-unsafe.rs | 106 +++++++++++++++++++++ 22 files changed, 202 insertions(+), 65 deletions(-) create mode 160000 src/rt/hoedown create mode 100644 src/test/compile-fail/specialization/defaultimpl/specialization-no-default-trait-implementations.rs create mode 100644 src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs (limited to 'src/libsyntax/parse') diff --git a/cargo b/cargo index c416fb60b11..8326a3683a9 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit c416fb60b11ecfd2a1ba0fb8567c9a92590b5d28 +Subproject commit 8326a3683a9045d825e4fdc4021af340ee3b3755 diff --git a/rls b/rls index 016cbc514cf..6ecff95fdc3 160000 --- a/rls +++ b/rls @@ -1 +1 @@ -Subproject commit 016cbc514cf44a2bd3fe806e8afa6b9c50287373 +Subproject commit 6ecff95fdc3ee7ceed2b9b0cc1a3a64876860bce diff --git a/src/compiler-rt b/src/compiler-rt index a8fc4c169fa..d30da544a8a 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit a8fc4c169fac43a5dc204d4fd56ddb1739f8c178 +Subproject commit d30da544a8afc5d78391dee270bdf40e74a215d3 diff --git a/src/doc/book b/src/doc/book index beea82b9230..ad7de198561 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit beea82b9230cd641dd1ca263cf31025ace4aebb5 +Subproject commit ad7de198561b3a12217ea2da76d796d9c7fc0ed3 diff --git a/src/doc/reference b/src/doc/reference index b060f732145..6b0de90d87d 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit b060f732145f2fa16df84c74e511df08a3a47c5d +Subproject commit 6b0de90d87dda15e323ef24cdf7ed873ac5cf4d3 diff --git a/src/grammar/parser-lalr.y b/src/grammar/parser-lalr.y index 3aa76d168df..69ba0c9098b 100644 --- a/src/grammar/parser-lalr.y +++ b/src/grammar/parser-lalr.y @@ -89,6 +89,7 @@ extern char *yytext; %token TRAIT %token TYPE %token UNSAFE +%token DEFAULT %token USE %token WHILE %token CONTINUE @@ -534,6 +535,11 @@ maybe_unsafe | %empty { $$ = mk_none(); } ; +maybe_default_impl +: IMPL { $$ = mk_none(); } +| DEFAULT IMPL { $$ = $1 } +; + trait_method : type_method { $$ = mk_node("Required", 1, $1); } | method { $$ = mk_node("Provided", 1, $1); } @@ -588,27 +594,27 @@ impl_method // they are ambiguous with traits. We do the same here, regrettably, // by splitting ty into ty and ty_prim. item_impl -: maybe_unsafe IMPL generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +: maybe_unsafe maybe_default_impl generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' { - $$ = mk_node("ItemImpl", 6, $1, $3, $4, $5, $7, $8); + $$ = mk_node("ItemImpl", 6, $1, $3, $4, $5, $7, $8, $2); } -| maybe_unsafe IMPL generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +| maybe_unsafe maybe_default_impl generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' { - $$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10); + $$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10, $2); } -| maybe_unsafe IMPL generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +| maybe_unsafe maybe_default_impl generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' { - $$ = mk_node("ItemImpl", 6, $3, $4, $6, $7, $9, $10); + $$ = mk_node("ItemImpl", 6, $3, $4, $6, $7, $9, $10, $2); } -| maybe_unsafe IMPL generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' +| maybe_unsafe maybe_default_impl generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' { - $$ = mk_node("ItemImplNeg", 7, $1, $3, $5, $7, $8, $10, $11); + $$ = mk_node("ItemImplNeg", 7, $1, $3, $5, $7, $8, $10, $11, $2); } -| maybe_unsafe IMPL generic_params trait_ref FOR DOTDOT '{' '}' +| maybe_unsafe maybe_default_impl generic_params trait_ref FOR DOTDOT '{' '}' { $$ = mk_node("ItemImplDefault", 3, $1, $3, $4); } -| maybe_unsafe IMPL generic_params '!' trait_ref FOR DOTDOT '{' '}' +| maybe_unsafe maybe_default_impl generic_params '!' trait_ref FOR DOTDOT '{' '}' { $$ = mk_node("ItemImplDefaultNeg", 3, $1, $3, $4); } @@ -1935,4 +1941,4 @@ brackets_delimited_token_trees $2, mk_node("TTTok", 1, mk_atom("]"))); } -; +; \ No newline at end of file diff --git a/src/jemalloc b/src/jemalloc index e058ca66169..11bfb0dcf85 160000 --- a/src/jemalloc +++ b/src/jemalloc @@ -1 +1 @@ -Subproject commit e058ca661692a8d01f8cf9d35939dfe3105ce968 +Subproject commit 11bfb0dcf85f7aa92abd30524bb1e42e18d108c6 diff --git a/src/liblibc b/src/liblibc index 05a2d197356..c34a802d1eb 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 05a2d197356ef253dfd985166576619ac9b6947f +Subproject commit c34a802d1eb037b44c5252078c7270b5472e0f65 diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index d072340d8c8..8dda297e897 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1362,6 +1362,9 @@ impl<'a> LoweringContext<'a> { } ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"), } + + // [1] `defaultness.has_value()` is necer called for an `impl`, always `true` in order to + // not cause an assertion failure inside the `lower_defaultness` function } fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem { diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 82e03a9fddc..3aeee1c1b98 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -933,7 +933,7 @@ impl_stable_hash_for!(enum hir::Item_ { ItemUnion(variant_data, generics), ItemTrait(unsafety, generics, bounds, item_refs), ItemDefaultImpl(unsafety, trait_ref), - ItemImpl(unsafety, impl_polarity, generics, trait_ref, ty, impl_item_refs) + ItemImpl(unsafety, impl_polarity, impl_defaultness, generics, trait_ref, ty, impl_item_refs) }); impl_stable_hash_for!(struct hir::TraitItemRef { diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 3251addcb32..60171f1a428 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -195,6 +195,7 @@ pub trait CrateStore { fn implementations_of_trait(&self, filter: Option) -> Vec; // impl info + fn impl_defaultness(&self, def: DefId) -> hir::Defaultness; fn impl_parent(&self, impl_def_id: DefId) -> Option; // trait/impl-item info @@ -329,6 +330,7 @@ impl CrateStore for DummyCrateStore { fn implementations_of_trait(&self, filter: Option) -> Vec { vec![] } // impl info + fn impl_defaultness(&self, def: DefId) -> hir::Defaultness { bug!("impl_defaultness") } fn impl_parent(&self, def: DefId) -> Option { bug!("impl_parent") } // trait/impl-item info diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index f417ad5b3d9..7675b2d00eb 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -33,7 +33,6 @@ use ty::subst::Subst; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; use util::common::FN_OUTPUT_NAME; -use hir::{self}; /// Depending on the stage of compilation, we want projection to be /// more or less conservative. @@ -924,28 +923,8 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // being invoked). node_item.item.defaultness.has_value() } else { - let is_default = match selcx.tcx() - .map - .as_local_node_id(node_item.node.def_id()) { - Some(node_id) => { - let item = selcx.tcx().map.expect_item(node_id); - if let hir::ItemImpl(_, _, defaultness, ..) = item.node { - defaultness.is_default() - } else { - false - } - } - None => { - selcx.tcx() - .global_tcx() - .sess - .cstore - .impl_defaultness(node_item.node.def_id()) - .is_default() - } - }; - - node_item.item.defaultness.is_default() || is_default + node_item.item.defaultness.is_default() || + selcx.tcx().impl_is_default(node_item.node.def_id()) }; // Only reveal a specializable default if we're past type-checking diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index d4245ec9b24..4aa7950de8f 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -13,6 +13,7 @@ use ty::subst::{Subst, Substs}; use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef}; use ty::outlives::Component; use util::nodemap::FxHashSet; +use hir::{self}; use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext, Normalized}; @@ -504,6 +505,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }; ty::Binder((trait_ref, sig.skip_binder().output())) } + + pub fn impl_is_default(self, node_item_def_id: DefId) -> bool { + match self.hir.as_local_node_id(node_item_def_id) { + Some(node_id) => { + let item = self.hir.expect_item(node_id); + if let hir::ItemImpl(_, _, defaultness, ..) = item.node { + defaultness.is_default() + } else { + false + } + } + None => { + self.global_tcx() + .sess + .cstore + .impl_defaultness(node_item_def_id) + .is_default() + } + } + } } pub enum TupleArgumentsFlag { Yes, No } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 618c1711dad..767114a37be 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -90,7 +90,6 @@ provide! { <'tcx> tcx, def_id, cdata associated_item => { cdata.get_associated_item(def_id.index) } impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) } impl_polarity => { cdata.get_impl_polarity(def_id.index) } - impl_defaultness => { cdata.get_impl_defaultness(def_id.index) } coerce_unsized_info => { cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| { bug!("coerce_unsized_info: `{:?}` is missing its info", def_id); @@ -179,6 +178,12 @@ impl CrateStore for cstore::CStore { result } + fn impl_defaultness(&self, def: DefId) -> hir::Defaultness + { + self.dep_graph.read(DepNode::MetaData(def)); + self.get_crate_data(def.krate).get_impl_defaultness(def.index) + } + fn impl_parent(&self, impl_def: DefId) -> Option { self.dep_graph.read(DepNode::MetaData(impl_def)); self.get_crate_data(impl_def.krate).get_parent_impl(impl_def.index) diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 933c3482474..5870903e771 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -416,6 +416,7 @@ pub struct ImplData<'tcx> { impl_stable_hash_for!(struct ImplData<'tcx> { polarity, + defaultness, parent_impl, coerce_unsized_info, trait_ref diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 36e59b4774a..507ac1efc2c 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -429,7 +429,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } None => { - if let Some(NodeItem(item)) = self.tcx.map.get_if_local(id) { + if let Some(NodeItem(item)) = self.tcx.hir.get_if_local(id) { if let hir::ItemImpl(_, _, _, _, _, ref ty, _) = item.node { trait_id = self.lookup_def_id(ty.id); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 74886e503a8..a00d1ad0eae 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1142,21 +1142,7 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let Some(parent) = parent { if parent.item.is_final() { - let is_final = match tcx.map.as_local_node_id(parent.node.def_id()) { - Some(node_id) => { - let item = tcx.map.expect_item(node_id); - if let hir::ItemImpl(_, _, defaultness, ..) = item.node { - defaultness.is_final() - } else { - true - } - } - None => { - tcx.global_tcx().sess.cstore.impl_defaultness(parent.node.def_id()).is_final() - } - }; - - if is_final { + if !tcx.impl_is_default(parent.node.def_id()) { report_forbidden_specialization(tcx, impl_item, parent.node.def_id()); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 660ce837043..0203c3b6299 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -309,7 +309,7 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeItem(item) => { match item.node { ItemFn(.., ref generics, _) | - ItemImpl(_, _, ref generics, ..) | + ItemImpl(_, _, _, ref generics, ..) | ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | @@ -825,7 +825,7 @@ fn generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeItem(item) => { match item.node { ItemFn(.., ref generics, _) | - ItemImpl(_, _, ref generics, ..) => generics, + ItemImpl(_, _, _, ref generics, ..) => generics, ItemTy(_, ref generics) | ItemEnum(_, ref generics) | @@ -1236,7 +1236,7 @@ fn predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeItem(item) => { match item.node { ItemFn(.., ref generics, _) | - ItemImpl(_, _, ref generics, ..) | + ItemImpl(_, _, _, ref generics, ..) | ItemTy(_, ref generics) | ItemEnum(_, ref generics) | ItemStruct(_, ref generics) | diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 58f81c8b3d7..2c10fff03db 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4918,6 +4918,14 @@ impl<'a> Parser<'a> { allowed to have generics"); } + match defaultness { + ast::Defaultness::Default => { + self.span_err(impl_span, "`default impl` is not allowed for \ + default trait implementations"); + } + _ => {} + } + self.expect(&token::OpenDelim(token::Brace))?; self.expect(&token::CloseDelim(token::Brace))?; Ok((keywords::Invalid.ident(), @@ -5760,13 +5768,13 @@ impl<'a> Parser<'a> { } if (self.check_keyword(keywords::Unsafe) && self.look_ahead(1, |t| t.is_keyword(keywords::Impl))) || - (self.check_keyword(keywords::Default) && - self.look_ahead(1, |t| t.is_keyword(keywords::Unsafe)) && + (self.check_keyword(keywords::Unsafe) && + self.look_ahead(1, |t| t.is_keyword(keywords::Default)) && self.look_ahead(2, |t| t.is_keyword(keywords::Impl))) { // IMPL ITEM - let defaultness = self.parse_defaultness()?; self.expect_keyword(keywords::Unsafe)?; + let defaultness = self.parse_defaultness()?; self.expect_keyword(keywords::Impl)?; let (ident, item_, diff --git a/src/rt/hoedown b/src/rt/hoedown new file mode 160000 index 00000000000..da282f1bb72 --- /dev/null +++ b/src/rt/hoedown @@ -0,0 +1 @@ +Subproject commit da282f1bb7277b4d30fa1599ee29ad8eb4dd2a92 diff --git a/src/test/compile-fail/specialization/defaultimpl/specialization-no-default-trait-implementations.rs b/src/test/compile-fail/specialization/defaultimpl/specialization-no-default-trait-implementations.rs new file mode 100644 index 00000000000..c1746d765dd --- /dev/null +++ b/src/test/compile-fail/specialization/defaultimpl/specialization-no-default-trait-implementations.rs @@ -0,0 +1,19 @@ +// 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. + +#![feature(specialization)] +#![feature(optin_builtin_traits)] + +trait Foo {} + +default impl Foo for .. {} +//~^ ERROR `default impl` is not allowed for default trait implementations + +fn main() {} diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs b/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs new file mode 100644 index 00000000000..9376d0db2df --- /dev/null +++ b/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs @@ -0,0 +1,106 @@ +// Copyright 2014 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(specialization)] + +// Tests a variety of basic specialization scenarios and method +// dispatch for them. + +unsafe trait Foo { + fn foo(&self) -> &'static str; +} + +unsafe default impl Foo for T { + fn foo(&self) -> &'static str { + "generic" + } +} + +unsafe default impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone" + } +} + +unsafe default impl Foo for (T, U) where T: Clone, U: Clone { + fn foo(&self) -> &'static str { + "generic pair" + } +} + +unsafe default impl Foo for (T, T) { + fn foo(&self) -> &'static str { + "generic uniform pair" + } +} + +unsafe default impl Foo for (u8, u32) { + fn foo(&self) -> &'static str { + "(u8, u32)" + } +} + +unsafe default impl Foo for (u8, u8) { + fn foo(&self) -> &'static str { + "(u8, u8)" + } +} + +unsafe default impl Foo for Vec { + fn foo(&self) -> &'static str { + "generic Vec" + } +} + +unsafe impl Foo for Vec { + fn foo(&self) -> &'static str { + "Vec" + } +} + +unsafe impl Foo for String { + fn foo(&self) -> &'static str { + "String" + } +} + +unsafe impl Foo for i32 { + fn foo(&self) -> &'static str { + "i32" + } +} + +struct NotClone; + +unsafe trait MyMarker {} +unsafe default impl Foo for T { + fn foo(&self) -> &'static str { + "generic Clone + MyMarker" + } +} + +#[derive(Clone)] +struct MarkedAndClone; +unsafe impl MyMarker for MarkedAndClone {} + +fn main() { + assert!(NotClone.foo() == "generic"); + assert!(0u8.foo() == "generic Clone"); + assert!(vec![NotClone].foo() == "generic"); + assert!(vec![0u8].foo() == "generic Vec"); + assert!(vec![0i32].foo() == "Vec"); + assert!(0i32.foo() == "i32"); + assert!(String::new().foo() == "String"); + assert!(((), 0).foo() == "generic pair"); + assert!(((), ()).foo() == "generic uniform pair"); + assert!((0u8, 0u32).foo() == "(u8, u32)"); + assert!((0u8, 0u8).foo() == "(u8, u8)"); + assert!(MarkedAndClone.foo() == "generic Clone + MyMarker"); +} -- cgit 1.4.1-3-g733a5 From b857a1a39fc29b8f241d8aa4c859ff4105cb160c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 27 Mar 2017 13:59:10 +0200 Subject: Update affected tests --- src/libsyntax/parse/parser.rs | 4 +--- src/test/compile-fail/issue-27842.rs | 2 +- src/test/ui/pub/pub-restricted.rs | 6 +++++- src/test/ui/pub/pub-restricted.stderr | 31 ++++++++++++++++------------ src/test/ui/span/issue-39018.stderr | 6 +++--- src/test/ui/span/suggestion-non-ascii.stderr | 5 +---- 6 files changed, 29 insertions(+), 25 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 1baf0d1b54c..53656d8c6c2 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5122,7 +5122,6 @@ impl<'a> Parser<'a> { } if self.check(&token::OpenDelim(token::Paren)) { - let start_span = self.span; // We don't `self.bump()` the `(` yet because this might be a struct definition where // `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`. // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so @@ -5165,8 +5164,7 @@ impl<'a> Parser<'a> { the path:", path); self.expect(&token::CloseDelim(token::Paren))?; // `)` - let sp = start_span.to(self.prev_span); - let mut err = self.span_fatal_help(sp, &msg, &suggestion); + let mut err = self.span_fatal_help(path_span, &msg, &suggestion); err.span_suggestion(path_span, &help_msg, format!("in {}", path)); err.emit(); // emit diagnostic, but continue with public visibility } diff --git a/src/test/compile-fail/issue-27842.rs b/src/test/compile-fail/issue-27842.rs index 28050a2ee90..f7cd4e03c3b 100644 --- a/src/test/compile-fail/issue-27842.rs +++ b/src/test/compile-fail/issue-27842.rs @@ -13,7 +13,7 @@ fn main() { // the case where we show a suggestion let _ = tup[0]; //~^ ERROR cannot index a value of type - //~| HELP to access tuple elements, use tuple indexing syntax as shown + //~| HELP to access tuple elements, use //~| SUGGESTION let _ = tup.0 // the case where we show just a general hint diff --git a/src/test/ui/pub/pub-restricted.rs b/src/test/ui/pub/pub-restricted.rs index 48e487f71a7..934ad24c167 100644 --- a/src/test/ui/pub/pub-restricted.rs +++ b/src/test/ui/pub/pub-restricted.rs @@ -34,4 +34,8 @@ mod y { } } -fn main() {} \ No newline at end of file +fn main() {} + +// test multichar names +mod xyz {} +pub (xyz) fn xyz() {} diff --git a/src/test/ui/pub/pub-restricted.stderr b/src/test/ui/pub/pub-restricted.stderr index 5bc230e8da3..7bee1791eab 100644 --- a/src/test/ui/pub/pub-restricted.stderr +++ b/src/test/ui/pub/pub-restricted.stderr @@ -1,41 +1,46 @@ error: incorrect visibility restriction - --> $DIR/pub-restricted.rs:15:5 + --> $DIR/pub-restricted.rs:15:6 | 15 | pub (a) fn afn() {} - | ^^^ + | ^ to make this visible only to module `a`, add `in` before the path: `in a` | = help: some possible visibility restrictions are: `pub(crate)`: visible only on the current crate `pub(super)`: visible only in the current module's parent `pub(in path::to::module)`: visible only on the specified path -help: to make this visible only to module `a`, add `in` before the path: - | pub (in a) fn afn() {} error: incorrect visibility restriction - --> $DIR/pub-restricted.rs:16:5 + --> $DIR/pub-restricted.rs:16:6 | 16 | pub (b) fn bfn() {} - | ^^^ + | ^ to make this visible only to module `b`, add `in` before the path: `in b` | = help: some possible visibility restrictions are: `pub(crate)`: visible only on the current crate `pub(super)`: visible only in the current module's parent `pub(in path::to::module)`: visible only on the specified path -help: to make this visible only to module `b`, add `in` before the path: - | pub (in b) fn bfn() {} error: incorrect visibility restriction - --> $DIR/pub-restricted.rs:32:13 + --> $DIR/pub-restricted.rs:32:14 | 32 | pub (a) invalid: usize, - | ^^^ + | ^ to make this visible only to module `a`, add `in` before the path: `in a` + | + = help: some possible visibility restrictions are: + `pub(crate)`: visible only on the current crate + `pub(super)`: visible only in the current module's parent + `pub(in path::to::module)`: visible only on the specified path + +error: incorrect visibility restriction + --> $DIR/pub-restricted.rs:41:6 + | +41 | pub (xyz) fn xyz() {} + | ^^^ to make this visible only to module `xyz`, add `in` before the path: `in xyz` | = help: some possible visibility restrictions are: `pub(crate)`: visible only on the current crate `pub(super)`: visible only in the current module's parent `pub(in path::to::module)`: visible only on the specified path -help: to make this visible only to module `a`, add `in` before the path: - | pub (in a) invalid: usize, error: visibilities can only be restricted to ancestor modules --> $DIR/pub-restricted.rs:33:17 @@ -43,5 +48,5 @@ error: visibilities can only be restricted to ancestor modules 33 | pub (in x) non_parent_invalid: usize, | ^ -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr index 9d6d4570c6b..46d39dac5ac 100644 --- a/src/test/ui/span/issue-39018.stderr +++ b/src/test/ui/span/issue-39018.stderr @@ -2,11 +2,11 @@ error[E0369]: binary operation `+` cannot be applied to type `&'static str` --> $DIR/issue-39018.rs:12:13 | 12 | let x = "Hello " + "World!"; - | ^^^^^^^^ + | ^^^^^^^^----------- + | | + | to_owned() can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left. `"Hello ".to_owned() + "World!"` | = note: `+` can't be used to concatenate two `&str` strings -help: to_owned() can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left. - | let x = "Hello ".to_owned() + "World!"; error[E0369]: binary operation `+` cannot be applied to type `World` --> $DIR/issue-39018.rs:17:13 diff --git a/src/test/ui/span/suggestion-non-ascii.stderr b/src/test/ui/span/suggestion-non-ascii.stderr index 385c211f393..7e0cf030d76 100644 --- a/src/test/ui/span/suggestion-non-ascii.stderr +++ b/src/test/ui/span/suggestion-non-ascii.stderr @@ -2,10 +2,7 @@ error: cannot index a value of type `({integer},)` --> $DIR/suggestion-non-ascii.rs:14:21 | 14 | println!("☃{}", tup[0]); - | ^^^^^^ - | -help: to access tuple elements, use tuple indexing syntax as shown - | println!("☃{}", tup.0); + | ^^^^^^ to access tuple elements, use `tup.0` error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From 3a5567bad45fbde0962263f484ebc76f750920e4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 28 Mar 2017 13:06:01 +0200 Subject: Address PR comments --- src/librustc_errors/emitter.rs | 4 +++- src/librustc_typeck/check/op.rs | 12 +++++++----- src/librustc_typeck/diagnostics.rs | 7 +++++++ src/libsyntax/parse/parser.rs | 4 +--- src/test/ui/pub/pub-restricted.stderr | 8 ++++---- src/test/ui/span/issue-39018.stderr | 7 ++++--- 6 files changed, 26 insertions(+), 16 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 8855859d7c4..085424ef7e6 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -37,7 +37,9 @@ impl Emitter for EmitterWriter { if let Some(sugg) = db.suggestion.clone() { assert_eq!(sugg.msp.primary_spans().len(), sugg.substitutes.len()); - if sugg.substitutes.len() == 1 { + if sugg.substitutes.len() == 1 && // don't display multispans as labels + sugg.msg.split_whitespace().count() < 10 && // don't display long messages as labels + sugg.substitutes[0].find('\n').is_none() { // don't display multiline suggestions as labels let msg = format!("{} `{}`", sugg.msg, sugg.substitutes[0]); primary_span.push_span_label(sugg.msp.primary_spans()[0], msg); } else { diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 6968a37361a..7d17cee9879 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -197,7 +197,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // error types are considered "builtin" if !lhs_ty.references_error() { if let IsAssign::Yes = is_assign { - struct_span_err!(self.tcx.sess, lhs_expr.span, E0368, + struct_span_err!(self.tcx.sess, expr.span, E0368, "binary assignment operation `{}=` \ cannot be applied to type `{}`", op.node.as_str(), @@ -207,7 +207,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { op.node.as_str(), lhs_ty)) .emit(); } else { - let mut err = struct_span_err!(self.tcx.sess, lhs_expr.span, E0369, + let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369, "binary operation `{}` cannot be applied to type `{}`", op.node.as_str(), lhs_ty); @@ -244,7 +244,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(missing_trait) = missing_trait { if missing_trait == "std::ops::Add" && - self.check_str_addition(lhs_expr, lhs_ty, + self.check_str_addition(expr, lhs_expr, lhs_ty, rhs_expr, rhs_ty_var, &mut err) { // This has nothing here because it means we did string // concatenation (e.g. "Hello " + "World!"). This means @@ -266,6 +266,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } fn check_str_addition(&self, + expr: &'gcx hir::Expr, lhs_expr: &'gcx hir::Expr, lhs_ty: Ty<'tcx>, rhs_expr: &'gcx hir::Expr, @@ -277,7 +278,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let TyRef(_, l_ty) = lhs_ty.sty { if let TyRef(_, r_ty) = rhs_ty.sty { if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr { - err.note("`+` can't be used to concatenate two `&str` strings"); + err.span_label(expr.span, + &"`+` can't be used to concatenate two `&str` strings"); let codemap = self.tcx.sess.codemap(); let suggestion = match codemap.span_to_snippet(lhs_expr.span) { @@ -289,7 +291,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { from a string reference. String concatenation \ appends the string on the right to the string \ on the left and may require reallocation. This \ - requires ownership of the string on the left:"), suggestion); + requires ownership of the string on the left."), suggestion); is_string_addition = true; } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 2bae6a0d9e1..54637269bc0 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3181,6 +3181,13 @@ x << 2; // ok! It is also possible to overload most operators for your own type by implementing traits from `std::ops`. + +String concatenation appends the string on the right to the string on the +left and may require reallocation. This requires ownership of the string +on the left. If something should be added to a string literal, move the +literal to the heap by allocating it with `to_owned()` like in +`"Your text".to_owned()`. + "##, E0370: r##" diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 53656d8c6c2..e1fe8f1b2eb 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5160,9 +5160,7 @@ impl<'a> Parser<'a> { `pub(in path::to::module)`: visible only on the specified path"##; let path = self.parse_path(PathStyle::Mod)?; let path_span = self.prev_span; - let help_msg = format!("to make this visible only to module `{}`, add `in` before \ - the path:", - path); + let help_msg = format!("make this visible only to module `{}` with `in`:", path); self.expect(&token::CloseDelim(token::Paren))?; // `)` let mut err = self.span_fatal_help(path_span, &msg, &suggestion); err.span_suggestion(path_span, &help_msg, format!("in {}", path)); diff --git a/src/test/ui/pub/pub-restricted.stderr b/src/test/ui/pub/pub-restricted.stderr index 7bee1791eab..760df5b5da0 100644 --- a/src/test/ui/pub/pub-restricted.stderr +++ b/src/test/ui/pub/pub-restricted.stderr @@ -2,7 +2,7 @@ error: incorrect visibility restriction --> $DIR/pub-restricted.rs:15:6 | 15 | pub (a) fn afn() {} - | ^ to make this visible only to module `a`, add `in` before the path: `in a` + | ^ make this visible only to module `a` with `in`: `in a` | = help: some possible visibility restrictions are: `pub(crate)`: visible only on the current crate @@ -13,7 +13,7 @@ error: incorrect visibility restriction --> $DIR/pub-restricted.rs:16:6 | 16 | pub (b) fn bfn() {} - | ^ to make this visible only to module `b`, add `in` before the path: `in b` + | ^ make this visible only to module `b` with `in`: `in b` | = help: some possible visibility restrictions are: `pub(crate)`: visible only on the current crate @@ -24,7 +24,7 @@ error: incorrect visibility restriction --> $DIR/pub-restricted.rs:32:14 | 32 | pub (a) invalid: usize, - | ^ to make this visible only to module `a`, add `in` before the path: `in a` + | ^ make this visible only to module `a` with `in`: `in a` | = help: some possible visibility restrictions are: `pub(crate)`: visible only on the current crate @@ -35,7 +35,7 @@ error: incorrect visibility restriction --> $DIR/pub-restricted.rs:41:6 | 41 | pub (xyz) fn xyz() {} - | ^^^ to make this visible only to module `xyz`, add `in` before the path: `in xyz` + | ^^^ make this visible only to module `xyz` with `in`: `in xyz` | = help: some possible visibility restrictions are: `pub(crate)`: visible only on the current crate diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr index b588238202e..cd3a41b037c 100644 --- a/src/test/ui/span/issue-39018.stderr +++ b/src/test/ui/span/issue-39018.stderr @@ -2,15 +2,16 @@ error[E0369]: binary operation `+` cannot be applied to type `&'static str` --> $DIR/issue-39018.rs:12:13 | 12 | let x = "Hello " + "World!"; - | ^^^^^^^^ `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left: `"Hello ".to_owned()` + | ^^^^^^^^^^^^^^^^^^^ `+` can't be used to concatenate two `&str` strings | - = note: `+` can't be used to concatenate two `&str` strings +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left. + | let x = "Hello ".to_owned() + "World!"; error[E0369]: binary operation `+` cannot be applied to type `World` --> $DIR/issue-39018.rs:17:13 | 17 | let y = World::Hello + World::Goodbye; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: an implementation of `std::ops::Add` might be missing for `World` -- cgit 1.4.1-3-g733a5 From f4b1e2af6836bcf30a8be05ff6a44df6f61b19f2 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 28 Mar 2017 14:10:16 +0200 Subject: Improve E0178 suggestion placement --- src/librustc_errors/emitter.rs | 9 ++++--- src/librustc_typeck/diagnostics.rs | 2 +- src/libsyntax/parse/parser.rs | 9 ++++--- src/test/compile-fail/E0178.rs | 29 ---------------------- ...t-object-reference-without-parens-suggestion.rs | 21 ---------------- src/test/ui/did_you_mean/E0178.rs | 21 ++++++++++++++++ src/test/ui/did_you_mean/E0178.stderr | 26 +++++++++++++++++++ ...t-object-reference-without-parens-suggestion.rs | 14 +++++++++++ ...ject-reference-without-parens-suggestion.stderr | 22 ++++++++++++++++ 9 files changed, 95 insertions(+), 58 deletions(-) delete mode 100644 src/test/compile-fail/E0178.rs delete mode 100644 src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs create mode 100644 src/test/ui/did_you_mean/E0178.rs create mode 100644 src/test/ui/did_you_mean/E0178.stderr create mode 100644 src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.rs create mode 100644 src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr (limited to 'src/libsyntax/parse') diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 085424ef7e6..68e58e230f8 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -37,9 +37,12 @@ impl Emitter for EmitterWriter { if let Some(sugg) = db.suggestion.clone() { assert_eq!(sugg.msp.primary_spans().len(), sugg.substitutes.len()); - if sugg.substitutes.len() == 1 && // don't display multispans as labels - sugg.msg.split_whitespace().count() < 10 && // don't display long messages as labels - sugg.substitutes[0].find('\n').is_none() { // don't display multiline suggestions as labels + // don't display multispans as labels + if sugg.substitutes.len() == 1 && + // don't display long messages as labels + sugg.msg.split_whitespace().count() < 10 && + // don't display multiline suggestions as labels + sugg.substitutes[0].find('\n').is_none() { let msg = format!("{} `{}`", sugg.msg, sugg.substitutes[0]); primary_span.push_span_label(sugg.msp.primary_spans()[0], msg); } else { diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 54637269bc0..0f42ee15ecf 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3185,7 +3185,7 @@ implementing traits from `std::ops`. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left. If something should be added to a string literal, move the -literal to the heap by allocating it with `to_owned()` like in +literal to the heap by allocating it with `to_owned()` like in `"Your text".to_owned()`. "##, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e1fe8f1b2eb..55098d77472 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1490,9 +1490,8 @@ impl<'a> Parser<'a> { let bounds = self.parse_ty_param_bounds()?; let sum_span = ty.span.to(self.prev_span); - let mut err = struct_span_err!(self.sess.span_diagnostic, ty.span, E0178, + let mut err = struct_span_err!(self.sess.span_diagnostic, sum_span, E0178, "expected a path on the left-hand side of `+`, not `{}`", pprust::ty_to_string(&ty)); - err.span_label(ty.span, &format!("expected a path")); match ty.node { TyKind::Rptr(ref lifetime, ref mut_ty) => { @@ -1511,9 +1510,11 @@ impl<'a> Parser<'a> { err.span_suggestion(sum_span, "try adding parentheses:", sum_with_parens); } TyKind::Ptr(..) | TyKind::BareFn(..) => { - help!(&mut err, "perhaps you forgot parentheses?"); + err.span_label(sum_span, &"perhaps you forgot parentheses?"); } - _ => {} + _ => { + err.span_label(sum_span, &"expected a path"); + }, } err.emit(); Ok(()) diff --git a/src/test/compile-fail/E0178.rs b/src/test/compile-fail/E0178.rs deleted file mode 100644 index 6527465e0b7..00000000000 --- a/src/test/compile-fail/E0178.rs +++ /dev/null @@ -1,29 +0,0 @@ -// 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. - -trait Foo {} - -struct Bar<'a> { - w: &'a Foo + Copy, - //~^ ERROR E0178 - //~| NOTE expected a path - x: &'a Foo + 'a, - //~^ ERROR E0178 - //~| NOTE expected a path - y: &'a mut Foo + 'a, - //~^ ERROR E0178 - //~| NOTE expected a path - z: fn() -> Foo + 'a, - //~^ ERROR E0178 - //~| NOTE expected a path -} - -fn main() { -} diff --git a/src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs b/src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs deleted file mode 100644 index f9f887b78b0..00000000000 --- a/src/test/compile-fail/trait-object-reference-without-parens-suggestion.rs +++ /dev/null @@ -1,21 +0,0 @@ -// 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. - -fn main() { - let _: &Copy + 'static; - //~^ ERROR expected a path - //~| HELP try adding parentheses - //~| SUGGESTION let _: &(Copy + 'static); - //~| ERROR the trait `std::marker::Copy` cannot be made into an object - let _: &'static Copy + 'static; - //~^ ERROR expected a path - //~| HELP try adding parentheses - //~| SUGGESTION let _: &'static (Copy + 'static); -} diff --git a/src/test/ui/did_you_mean/E0178.rs b/src/test/ui/did_you_mean/E0178.rs new file mode 100644 index 00000000000..8fb6c9815ce --- /dev/null +++ b/src/test/ui/did_you_mean/E0178.rs @@ -0,0 +1,21 @@ +// 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. + +trait Foo {} + +struct Bar<'a> { + w: &'a Foo + Copy, + x: &'a Foo + 'a, + y: &'a mut Foo + 'a, + z: fn() -> Foo + 'a, +} + +fn main() { +} diff --git a/src/test/ui/did_you_mean/E0178.stderr b/src/test/ui/did_you_mean/E0178.stderr new file mode 100644 index 00000000000..86f51a28a52 --- /dev/null +++ b/src/test/ui/did_you_mean/E0178.stderr @@ -0,0 +1,26 @@ +error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo` + --> $DIR/E0178.rs:14:8 + | +14 | w: &'a Foo + Copy, + | ^^^^^^^^^^^^^^ try adding parentheses: `&'a (Foo + Copy)` + +error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo` + --> $DIR/E0178.rs:15:8 + | +15 | x: &'a Foo + 'a, + | ^^^^^^^^^^^^ try adding parentheses: `&'a (Foo + 'a)` + +error[E0178]: expected a path on the left-hand side of `+`, not `&'a mut Foo` + --> $DIR/E0178.rs:16:8 + | +16 | y: &'a mut Foo + 'a, + | ^^^^^^^^^^^^^^^^ try adding parentheses: `&'a mut (Foo + 'a)` + +error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> Foo` + --> $DIR/E0178.rs:17:8 + | +17 | z: fn() -> Foo + 'a, + | ^^^^^^^^^^^^^^^^ perhaps you forgot parentheses? + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.rs b/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.rs new file mode 100644 index 00000000000..11757abae9c --- /dev/null +++ b/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.rs @@ -0,0 +1,14 @@ +// 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. + +fn main() { + let _: &Copy + 'static; + let _: &'static Copy + 'static; +} diff --git a/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr b/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr new file mode 100644 index 00000000000..cffa0474d22 --- /dev/null +++ b/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr @@ -0,0 +1,22 @@ +error[E0178]: expected a path on the left-hand side of `+`, not `&Copy` + --> $DIR/trait-object-reference-without-parens-suggestion.rs:12:12 + | +12 | let _: &Copy + 'static; + | ^^^^^^^^^^^^^^^ try adding parentheses: `&(Copy + 'static)` + +error[E0178]: expected a path on the left-hand side of `+`, not `&'static Copy` + --> $DIR/trait-object-reference-without-parens-suggestion.rs:13:12 + | +13 | let _: &'static Copy + 'static; + | ^^^^^^^^^^^^^^^^^^^^^^^ try adding parentheses: `&'static (Copy + 'static)` + +error[E0038]: the trait `std::marker::Copy` cannot be made into an object + --> $DIR/trait-object-reference-without-parens-suggestion.rs:12:12 + | +12 | let _: &Copy + 'static; + | ^^^^^ the trait `std::marker::Copy` cannot be made into an object + | + = note: the trait cannot require that `Self : Sized` + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 3f97b2a65c31a1c53c29d233d6b37b0258e4a6b2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 24 Apr 2017 16:26:04 +0200 Subject: Add ui tests --- src/libsyntax/parse/parser.rs | 11 ++++------- src/test/compile-fail/auxiliary/foo/bar.rs | 11 ----------- src/test/compile-fail/auxiliary/foo/mod.rs | 11 ----------- src/test/compile-fail/invalid-module-declaration.rs | 20 -------------------- .../invalid-module-declaration/auxiliary/foo/bar.rs | 11 +++++++++++ .../invalid-module-declaration/auxiliary/foo/mod.rs | 11 +++++++++++ .../invalid-module-declaration.rs | 20 ++++++++++++++++++++ .../invalid-module-declaration.stderr | 14 ++++++++++++++ 8 files changed, 60 insertions(+), 49 deletions(-) delete mode 100644 src/test/compile-fail/auxiliary/foo/bar.rs delete mode 100644 src/test/compile-fail/auxiliary/foo/mod.rs delete mode 100644 src/test/compile-fail/invalid-module-declaration.rs create mode 100644 src/test/ui/invalid-module-declaration/auxiliary/foo/bar.rs create mode 100644 src/test/ui/invalid-module-declaration/auxiliary/foo/mod.rs create mode 100644 src/test/ui/invalid-module-declaration/invalid-module-declaration.rs create mode 100644 src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9df791c1c12..afdb0cc4fdb 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -57,10 +57,10 @@ use tokenstream::{self, Delimited, ThinTokenStream, TokenTree, TokenStream}; use symbol::{Symbol, keywords}; use util::ThinVec; +use std::cmp; use std::collections::HashSet; use std::mem; -use std::path::{Path, PathBuf}; -use std::rc::Rc; +use std::path::{self, Path, PathBuf}; use std::slice; bitflags! { @@ -5367,7 +5367,7 @@ impl<'a> Parser<'a> { "cannot declare a new module at this location"); if id_sp != syntax_pos::DUMMY_SP { let src_path = PathBuf::from(self.sess.codemap().span_to_filename(id_sp)); - if let Some(stem) = src_path.clone().file_stem() { + if let Some(stem) = src_path.file_stem() { let mut dest_path = src_path.clone(); dest_path.set_file_name(stem); dest_path.push("mod.rs"); @@ -5385,10 +5385,7 @@ impl<'a> Parser<'a> { } Err(err) } else { - match paths.result { - Ok(succ) => Ok(succ), - Err(err) => Err(self.span_fatal_err(id_sp, err)), - } + paths.result.map_err(|err| self.span_fatal_err(id_sp, err)) } } diff --git a/src/test/compile-fail/auxiliary/foo/bar.rs b/src/test/compile-fail/auxiliary/foo/bar.rs deleted file mode 100644 index 4b6b4f5ebf8..00000000000 --- a/src/test/compile-fail/auxiliary/foo/bar.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2017 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. - -pub mod baz; diff --git a/src/test/compile-fail/auxiliary/foo/mod.rs b/src/test/compile-fail/auxiliary/foo/mod.rs deleted file mode 100644 index 6d77fb60a35..00000000000 --- a/src/test/compile-fail/auxiliary/foo/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2017 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. - -pub mod bar; diff --git a/src/test/compile-fail/invalid-module-declaration.rs b/src/test/compile-fail/invalid-module-declaration.rs deleted file mode 100644 index c15cfb8cc8e..00000000000 --- a/src/test/compile-fail/invalid-module-declaration.rs +++ /dev/null @@ -1,20 +0,0 @@ -// 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. - -// ignore-tidy-linelength - -// error-pattern: cannot declare a new module at this location -// error-pattern: maybe move this module - -mod auxiliary { - mod foo; -} - -fn main() {} diff --git a/src/test/ui/invalid-module-declaration/auxiliary/foo/bar.rs b/src/test/ui/invalid-module-declaration/auxiliary/foo/bar.rs new file mode 100644 index 00000000000..4b6b4f5ebf8 --- /dev/null +++ b/src/test/ui/invalid-module-declaration/auxiliary/foo/bar.rs @@ -0,0 +1,11 @@ +// Copyright 2017 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. + +pub mod baz; diff --git a/src/test/ui/invalid-module-declaration/auxiliary/foo/mod.rs b/src/test/ui/invalid-module-declaration/auxiliary/foo/mod.rs new file mode 100644 index 00000000000..6d77fb60a35 --- /dev/null +++ b/src/test/ui/invalid-module-declaration/auxiliary/foo/mod.rs @@ -0,0 +1,11 @@ +// Copyright 2017 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. + +pub mod bar; diff --git a/src/test/ui/invalid-module-declaration/invalid-module-declaration.rs b/src/test/ui/invalid-module-declaration/invalid-module-declaration.rs new file mode 100644 index 00000000000..c15cfb8cc8e --- /dev/null +++ b/src/test/ui/invalid-module-declaration/invalid-module-declaration.rs @@ -0,0 +1,20 @@ +// 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. + +// ignore-tidy-linelength + +// error-pattern: cannot declare a new module at this location +// error-pattern: maybe move this module + +mod auxiliary { + mod foo; +} + +fn main() {} diff --git a/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr b/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr new file mode 100644 index 00000000000..3e9b21cdb74 --- /dev/null +++ b/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr @@ -0,0 +1,14 @@ +error: cannot declare a new module at this location + --> $DIR/auxiliary/foo/bar.rs:11:9 + | +11 | pub mod baz; + | ^^^ + | +note: maybe move this module `$DIR/auxiliary/foo/bar.rs` to its own directory via `$DIR/auxiliary/foo/bar/mod.rs` + --> $DIR/auxiliary/foo/bar.rs:11:9 + | +11 | pub mod baz; + | ^^^ + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From d349e87d61745d402f6e38727beb62a6525a2153 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 22 Feb 2017 23:59:40 +0300 Subject: Parse trait object types starting with a lifetime bound --- src/libsyntax/parse/parser.rs | 4 +-- .../compile-fail/trait-object-macro-matcher.rs | 2 ++ .../compile-fail/trait-object-vs-lifetime-2.rs | 23 +++++++++++++++++ src/test/compile-fail/trait-object-vs-lifetime.rs | 29 ++++++++++++++++++++++ src/test/run-pass/trait-object-lifetime-first.rs | 22 ++++++++++++++++ 5 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/trait-object-vs-lifetime-2.rs create mode 100644 src/test/compile-fail/trait-object-vs-lifetime.rs create mode 100644 src/test/run-pass/trait-object-lifetime-first.rs (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 1baf0d1b54c..c7f4512301c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1451,9 +1451,9 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(keywords::Impl) { // FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511). TyKind::ImplTrait(self.parse_ty_param_bounds()?) - } else if self.check(&token::Question) { + } else if self.check(&token::Question) || + self.check_lifetime() && self.look_ahead(1, |t| t == &token::BinOp(token::Plus)){ // Bound list (trait object type) - // Bound lists starting with `'lt` are not currently supported (#40043) TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?) } else { let msg = format!("expected type, found {}", self.this_token_descr()); diff --git a/src/test/compile-fail/trait-object-macro-matcher.rs b/src/test/compile-fail/trait-object-macro-matcher.rs index de80b04b865..8497a699e97 100644 --- a/src/test/compile-fail/trait-object-macro-matcher.rs +++ b/src/test/compile-fail/trait-object-macro-matcher.rs @@ -16,4 +16,6 @@ macro_rules! m { fn main() { m!(Copy + Send + 'static); //~ ERROR the trait `std::marker::Copy` cannot be made into an object + m!('static + Send); + m!('static +); //~ ERROR at least one non-builtin trait is required for an object type } diff --git a/src/test/compile-fail/trait-object-vs-lifetime-2.rs b/src/test/compile-fail/trait-object-vs-lifetime-2.rs new file mode 100644 index 00000000000..9801cac4714 --- /dev/null +++ b/src/test/compile-fail/trait-object-vs-lifetime-2.rs @@ -0,0 +1,23 @@ +// Copyright 2017 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. + +// A few contrived examples where lifetime should (or should not) be parsed as an object type. +// Lifetimes parsed as types are still rejected later by semantic checks. + +// compile-flags: -Z continue-parse-after-error + +// `'static` is a lifetime, `'static +` is a type, `'a` is a type +fn g() where + 'static: 'static, + 'static +: 'static + Copy, + //~^ ERROR at least one non-builtin trait is required for an object type +{} + +fn main() {} diff --git a/src/test/compile-fail/trait-object-vs-lifetime.rs b/src/test/compile-fail/trait-object-vs-lifetime.rs new file mode 100644 index 00000000000..a70141edc29 --- /dev/null +++ b/src/test/compile-fail/trait-object-vs-lifetime.rs @@ -0,0 +1,29 @@ +// Copyright 2017 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. + +// A few contrived examples where lifetime should (or should not) be parsed as an object type. +// Lifetimes parsed as types are still rejected later by semantic checks. + +// compile-flags: -Z continue-parse-after-error + +struct S<'a, T>(&'a u8, T); + +fn main() { + // `'static` is a lifetime argument, `'static +` is a type argument + let _: S<'static, u8>; + let _: S<'static, 'static +>; + //~^ at least one non-builtin trait is required for an object type + let _: S<'static, 'static>; + //~^ ERROR wrong number of lifetime parameters: expected 1, found 2 + //~| ERROR wrong number of type arguments: expected 1, found 0 + let _: S<'static +, 'static>; + //~^ ERROR lifetime parameters must be declared prior to type parameters + //~| ERROR at least one non-builtin trait is required for an object type +} diff --git a/src/test/run-pass/trait-object-lifetime-first.rs b/src/test/run-pass/trait-object-lifetime-first.rs new file mode 100644 index 00000000000..f269fe90d4b --- /dev/null +++ b/src/test/run-pass/trait-object-lifetime-first.rs @@ -0,0 +1,22 @@ +// Copyright 2017 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. + +use std::fmt::Display; + +static BYTE: u8 = 33; + +fn main() { + let x: &('static + Display) = &BYTE; + let y: Box<'static + Display> = Box::new(BYTE); + let xstr = format!("{}", x); + let ystr = format!("{}", y); + assert_eq!(xstr, "33"); + assert_eq!(ystr, "33"); +} -- cgit 1.4.1-3-g733a5 From 39ffea31df73b20d5549330d446713e56e60e801 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 24 Apr 2017 19:01:19 +0200 Subject: Implement a file-path remapping feature in support of debuginfo and reproducible builds. --- src/grammar/verify.rs | 2 +- src/librustc/session/config.rs | 15 +- src/librustc/session/mod.rs | 29 ++- src/librustc_driver/lib.rs | 2 +- src/librustc_driver/test.rs | 4 +- src/librustc_metadata/cstore_impl.rs | 2 +- src/librustc_metadata/decoder.rs | 4 +- src/librustc_metadata/encoder.rs | 32 ++- src/librustc_save_analysis/dump_visitor.rs | 2 + src/librustc_trans/debuginfo/create_scope_map.rs | 23 +- src/librustc_trans/debuginfo/metadata.rs | 91 ++++---- src/librustc_trans/debuginfo/mod.rs | 23 +- src/librustc_trans/debuginfo/namespace.rs | 2 +- src/librustc_trans/mir/mod.rs | 6 +- src/librustdoc/core.rs | 2 +- src/librustdoc/html/highlight.rs | 10 +- src/librustdoc/test.rs | 4 +- src/libsyntax/codemap.rs | 101 ++++++--- src/libsyntax/ext/expand.rs | 2 +- src/libsyntax/ext/source_util.rs | 4 +- src/libsyntax/json.rs | 5 +- src/libsyntax/parse/lexer/comments.rs | 4 +- src/libsyntax/parse/lexer/mod.rs | 32 +-- src/libsyntax/parse/mod.rs | 16 +- src/libsyntax/test_snippet.rs | 6 +- src/libsyntax/util/parser_testing.rs | 15 +- src/libsyntax_pos/lib.rs | 13 +- src/test/codegen/remap_path_prefix.rs | 19 ++ src/test/compile-fail-fulldeps/qquote.rs | 3 +- src/test/run-fail-fulldeps/qquote.rs | 2 +- src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs | 9 +- src/test/run-pass-fulldeps/qquote.rs | 3 +- src/tools/compiletest/src/header.rs | 271 +++++++++++++---------- src/tools/compiletest/src/runtest.rs | 17 +- 34 files changed, 462 insertions(+), 313 deletions(-) create mode 100644 src/test/codegen/remap_path_prefix.rs (limited to 'src/libsyntax/parse') diff --git a/src/grammar/verify.rs b/src/grammar/verify.rs index bd28a63c5f4..3ac043f7aa9 100644 --- a/src/grammar/verify.rs +++ b/src/grammar/verify.rs @@ -296,7 +296,7 @@ fn main() { syntax::errors::registry::Registry::new(&[]), Rc::new(DummyCrateStore)); let filemap = session.parse_sess.codemap() - .new_filemap("".to_string(), None, code); + .new_filemap("".to_string(), code); let mut lexer = lexer::StringReader::new(session.diagnostic(), filemap); let cm = session.codemap(); diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index fadb1844008..888ed2a6d18 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -25,6 +25,7 @@ use lint; use middle::cstore; use syntax::ast::{self, IntTy, UintTy}; +use syntax::codemap::FilePathMapping; use syntax::parse::token; use syntax::parse; use syntax::symbol::Symbol; @@ -492,6 +493,14 @@ impl Options { self.incremental.is_none() || self.cg.codegen_units == 1 } + + pub fn file_path_mapping(&self) -> FilePathMapping { + FilePathMapping::new( + self.debugging_opts.remap_path_prefix_from.iter().zip( + self.debugging_opts.remap_path_prefix_to.iter() + ).map(|(src, dst)| (src.clone(), dst.clone())).collect() + ) + } } // The type of entry function, so @@ -1012,6 +1021,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "Set the optimization fuel quota for a crate."), print_fuel: Option = (None, parse_opt_string, [TRACKED], "Make Rustc print the total optimization fuel used by a crate."), + remap_path_prefix_from: Vec = (vec![], parse_string_push, [TRACKED], + "add a source pattern to the file path remapping config"), + remap_path_prefix_to: Vec = (vec![], parse_string_push, [TRACKED], + "add a mapping target to the file path remapping config"), } pub fn default_lib_output() -> CrateType { @@ -1319,7 +1332,7 @@ pub fn rustc_optgroups() -> Vec { // Convert strings provided as --cfg [cfgspec] into a crate_cfg pub fn parse_cfgspecs(cfgspecs: Vec ) -> ast::CrateConfig { cfgspecs.into_iter().map(|s| { - let sess = parse::ParseSess::new(); + let sess = parse::ParseSess::new(FilePathMapping::empty()); let mut parser = parse::new_parser_from_source_str(&sess, "cfgspec".to_string(), s.to_string()); diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index adc9aabb8c7..c8732c31663 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -74,8 +74,10 @@ pub struct Session { // The name of the root source file of the crate, in the local file system. // The path is always expected to be absolute. `None` means that there is no // source file. - pub local_crate_source_file: Option, - pub working_dir: PathBuf, + pub local_crate_source_file: Option, + // The directory the compiler has been executed in plus a flag indicating + // if the value stored here has been affected by path remapping. + pub working_dir: (String, bool), pub lint_store: RefCell, pub lints: RefCell, /// Set of (LintId, span, message) tuples tracking lint (sub)diagnostics @@ -553,12 +555,14 @@ pub fn build_session(sopts: config::Options, registry: errors::registry::Registry, cstore: Rc) -> Session { + let file_path_mapping = sopts.file_path_mapping(); + build_session_with_codemap(sopts, dep_graph, local_crate_source_file, registry, cstore, - Rc::new(codemap::CodeMap::new()), + Rc::new(codemap::CodeMap::new(file_path_mapping)), None) } @@ -622,7 +626,7 @@ pub fn build_session_(sopts: config::Options, Ok(t) => t, Err(e) => { panic!(span_diagnostic.fatal(&format!("Error loading host specification: {}", e))); - } + } }; let target_cfg = config::build_target_config(&sopts, &span_diagnostic); let p_s = parse::ParseSess::with_span_handler(span_diagnostic, codemap); @@ -631,14 +635,12 @@ pub fn build_session_(sopts: config::Options, None => Some(filesearch::get_or_default_sysroot()) }; + let file_path_mapping = sopts.file_path_mapping(); + // Make the path absolute, if necessary - let local_crate_source_file = local_crate_source_file.map(|path| - if path.is_absolute() { - path.clone() - } else { - env::current_dir().unwrap().join(&path) - } - ); + let local_crate_source_file = local_crate_source_file.map(|path| { + file_path_mapping.map_prefix(path.to_string_lossy().into_owned()).0 + }); let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone()); let optimization_fuel_limit = Cell::new(sopts.debugging_opts.fuel.as_ref() @@ -646,6 +648,9 @@ pub fn build_session_(sopts: config::Options, let print_fuel_crate = sopts.debugging_opts.print_fuel.clone(); let print_fuel = Cell::new(0); + let working_dir = env::current_dir().unwrap().to_string_lossy().into_owned(); + let working_dir = file_path_mapping.map_prefix(working_dir); + let sess = Session { dep_graph: dep_graph.clone(), target: target_cfg, @@ -660,7 +665,7 @@ pub fn build_session_(sopts: config::Options, derive_registrar_fn: Cell::new(None), default_sysroot: default_sysroot, local_crate_source_file: local_crate_source_file, - working_dir: env::current_dir().unwrap(), + working_dir: working_dir, lint_store: RefCell::new(lint::LintStore::new()), lints: RefCell::new(lint::LintTable::new()), one_time_diagnostics: RefCell::new(FxHashSet()), diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 1a892b73aa5..e4ed2b8eb8f 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -206,7 +206,7 @@ pub fn run_compiler<'a>(args: &[String], let cstore = Rc::new(CStore::new(&dep_graph)); let loader = file_loader.unwrap_or(box RealFileLoader); - let codemap = Rc::new(CodeMap::with_file_loader(loader)); + let codemap = Rc::new(CodeMap::with_file_loader(loader, sopts.file_path_mapping())); let mut sess = session::build_session_with_codemap( sopts, &dep_graph, input_file_path, descriptions, cstore.clone(), codemap, emitter_dest, ); diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 147d6558e19..a19bc4aea2c 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -31,7 +31,7 @@ use rustc::session::{self, config}; use std::rc::Rc; use syntax::ast; use syntax::abi::Abi; -use syntax::codemap::CodeMap; +use syntax::codemap::{CodeMap, FilePathMapping}; use errors; use errors::emitter::Emitter; use errors::{Level, DiagnosticBuilder}; @@ -108,7 +108,7 @@ fn test_env(source_string: &str, &dep_graph, None, diagnostic_handler, - Rc::new(CodeMap::new()), + Rc::new(CodeMap::new(FilePathMapping::empty())), cstore.clone()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let input = config::Input::Str { diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index f310279ea3c..b7f571cfd2b 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -395,7 +395,7 @@ impl CrateStore for cstore::CStore { let (name, def) = data.get_macro(id.index); let source_name = format!("<{} macros>", name); - let filemap = sess.parse_sess.codemap().new_filemap(source_name, None, def.body); + let filemap = sess.parse_sess.codemap().new_filemap(source_name, def.body); let local_span = Span { lo: filemap.start_pos, hi: filemap.end_pos, ctxt: NO_EXPANSION }; let body = filemap_to_stream(&sess.parse_sess, filemap); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 1656d489269..626dbf1a84f 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1134,7 +1134,7 @@ impl<'a, 'tcx> CrateMetadata { // We can't reuse an existing FileMap, so allocate a new one // containing the information we need. let syntax_pos::FileMap { name, - abs_path, + name_was_remapped, start_pos, end_pos, lines, @@ -1158,7 +1158,7 @@ impl<'a, 'tcx> CrateMetadata { } let local_version = local_codemap.new_imported_filemap(name, - abs_path, + name_was_remapped, source_length, lines, multibyte_chars); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 783e7604cda..22b020439a4 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -30,6 +30,7 @@ use std::hash::Hash; use std::intrinsics; use std::io::prelude::*; use std::io::Cursor; +use std::path::Path; use std::rc::Rc; use std::u32; use syntax::ast::{self, CRATE_NODE_ID}; @@ -1268,13 +1269,40 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_codemap(&mut self) -> LazySeq { let codemap = self.tcx.sess.codemap(); let all_filemaps = codemap.files.borrow(); - self.lazy_seq_ref(all_filemaps.iter() + let adapted = all_filemaps.iter() .filter(|filemap| { // No need to re-export imported filemaps, as any downstream // crate will import them from their original source. !filemap.is_imported() }) - .map(|filemap| &**filemap)) + .map(|filemap| { + // When exporting FileMaps, we expand all paths to absolute + // paths because any relative paths are potentially relative to + // a wrong directory. + // However, if a path has been modified via + // `-Zremap-path-prefix` we assume the user has already set + // things up the way they want and don't touch the path values + // anymore. + let name = Path::new(&filemap.name); + let (ref working_dir, working_dir_was_remapped) = self.tcx.sess.working_dir; + if filemap.name_was_remapped || + (name.is_relative() && working_dir_was_remapped) { + // This path of this FileMap has been modified by + // path-remapping, so we use it verbatim (and avoid cloning + // the whole map in the process). + filemap.clone() + } else { + let mut adapted = (**filemap).clone(); + let abs_path = Path::new(working_dir).join(name) + .to_string_lossy() + .into_owned(); + adapted.name = abs_path; + Rc::new(adapted) + } + }) + .collect::>(); + + self.lazy_seq_ref(adapted.iter().map(|fm| &**fm)) } fn encode_def_path_table(&mut self) -> Lazy { diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 9e3e727d4bd..c84e0eba6aa 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -37,6 +37,7 @@ use rustc::ty::{self, TyCtxt, AssociatedItemContainer}; use std::collections::HashSet; use std::collections::hash_map::DefaultHasher; use std::hash::*; +use std::path::Path; use syntax::ast::{self, NodeId, PatKind, Attribute, CRATE_NODE_ID}; use syntax::parse::token; @@ -128,6 +129,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) { let source_file = self.tcx.sess.local_crate_source_file.as_ref(); let crate_root = source_file.map(|source_file| { + let source_file = Path::new(source_file); match source_file.file_name() { Some(_) => source_file.parent().unwrap().display().to_string(), None => source_file.display().to_string(), diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs index 3d074c31c8a..ae618c7e170 100644 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/debuginfo/create_scope_map.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::FunctionDebugContext; +use super::{FunctionDebugContext, FunctionDebugContextData}; use super::metadata::file_metadata; use super::utils::{DIB, span_start}; use llvm; -use llvm::debuginfo::{DIScope, DISubprogram}; +use llvm::debuginfo::DIScope; use common::CrateContext; use rustc::mir::{Mir, VisibilityScope}; @@ -53,8 +53,8 @@ pub fn create_mir_scopes(ccx: &CrateContext, mir: &Mir, debug_context: &Function }; let mut scopes = IndexVec::from_elem(null_scope, &mir.visibility_scopes); - let fn_metadata = match *debug_context { - FunctionDebugContext::RegularContext(ref data) => data.fn_metadata, + let debug_context = match *debug_context { + FunctionDebugContext::RegularContext(ref data) => data, FunctionDebugContext::DebugInfoDisabled | FunctionDebugContext::FunctionWithoutDebugInfo => { return scopes; @@ -71,7 +71,7 @@ pub fn create_mir_scopes(ccx: &CrateContext, mir: &Mir, debug_context: &Function // Instantiate all scopes. for idx in 0..mir.visibility_scopes.len() { let scope = VisibilityScope::new(idx); - make_mir_scope(ccx, &mir, &has_variables, fn_metadata, scope, &mut scopes); + make_mir_scope(ccx, &mir, &has_variables, debug_context, scope, &mut scopes); } scopes @@ -80,7 +80,7 @@ pub fn create_mir_scopes(ccx: &CrateContext, mir: &Mir, debug_context: &Function fn make_mir_scope(ccx: &CrateContext, mir: &Mir, has_variables: &BitVector, - fn_metadata: DISubprogram, + debug_context: &FunctionDebugContextData, scope: VisibilityScope, scopes: &mut IndexVec) { if scopes[scope].is_valid() { @@ -89,13 +89,13 @@ fn make_mir_scope(ccx: &CrateContext, let scope_data = &mir.visibility_scopes[scope]; let parent_scope = if let Some(parent) = scope_data.parent_scope { - make_mir_scope(ccx, mir, has_variables, fn_metadata, parent, scopes); + make_mir_scope(ccx, mir, has_variables, debug_context, parent, scopes); scopes[parent] } else { // The root is the function itself. let loc = span_start(ccx, mir.span); scopes[scope] = MirDebugScope { - scope_metadata: fn_metadata, + scope_metadata: debug_context.fn_metadata, file_start_pos: loc.file.start_pos, file_end_pos: loc.file.end_pos, }; @@ -109,14 +109,17 @@ fn make_mir_scope(ccx: &CrateContext, // However, we don't skip creating a nested scope if // our parent is the root, because we might want to // put arguments in the root and not have shadowing. - if parent_scope.scope_metadata != fn_metadata { + if parent_scope.scope_metadata != debug_context.fn_metadata { scopes[scope] = parent_scope; return; } } let loc = span_start(ccx, scope_data.span); - let file_metadata = file_metadata(ccx, &loc.file.name, &loc.file.abs_path); + let file_metadata = file_metadata(ccx, + &loc.file.name, + debug_context.defining_crate); + let scope_metadata = unsafe { llvm::LLVMRustDIBuilderCreateLexicalBlock( DIB(ccx), diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 1f4756a94ea..188f8ee3366 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -26,7 +26,7 @@ use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType, DILexicalBlock, DIFlags}; use rustc::hir::def::CtorKind; -use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; use rustc::ty::fold::TypeVisitor; use rustc::ty::subst::Substs; use rustc::ty::util::TypeIdHasher; @@ -39,14 +39,12 @@ use rustc::ty::{self, AdtKind, Ty}; use rustc::ty::layout::{self, LayoutTyper}; use session::config; use util::nodemap::FxHashMap; -use util::common::path2cstr; use libc::{c_uint, c_longlong}; use std::ffi::CString; -use std::path::Path; use std::ptr; use syntax::ast; -use syntax::symbol::{Interner, InternedString}; +use syntax::symbol::{Interner, InternedString, Symbol}; use syntax_pos::{self, Span}; @@ -349,8 +347,7 @@ fn vec_slice_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, assert!(member_descriptions.len() == member_llvm_types.len()); - let loc = span_start(cx, span); - let file_metadata = file_metadata(cx, &loc.file.name, &loc.file.abs_path); + let file_metadata = unknown_file_metadata(cx); let metadata = composite_type_metadata(cx, slice_llvm_type, @@ -659,44 +656,51 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, metadata } -pub fn file_metadata(cx: &CrateContext, path: &str, full_path: &Option) -> DIFile { - // FIXME (#9639): This needs to handle non-utf8 paths - let work_dir = cx.sess().working_dir.to_str().unwrap(); - let file_name = - full_path.as_ref().map(|p| p.as_str()).unwrap_or_else(|| { - if path.starts_with(work_dir) { - &path[work_dir.len() + 1..path.len()] - } else { - path - } - }); +pub fn file_metadata(cx: &CrateContext, + file_name: &str, + defining_crate: CrateNum) -> DIFile { + debug!("file_metadata: file_name: {}, defining_crate: {}", + file_name, + defining_crate); - file_metadata_(cx, path, file_name, &work_dir) + let directory = if defining_crate == LOCAL_CRATE { + &cx.sess().working_dir.0[..] + } else { + // If the path comes from an upstream crate we assume it has been made + // independent of the compiler's working directory one way or another. + "" + }; + + file_metadata_raw(cx, file_name, directory) } pub fn unknown_file_metadata(cx: &CrateContext) -> DIFile { - // Regular filenames should not be empty, so we abuse an empty name as the - // key for the special unknown file metadata - file_metadata_(cx, "", "", "") - + file_metadata_raw(cx, "", "") } -fn file_metadata_(cx: &CrateContext, key: &str, file_name: &str, work_dir: &str) -> DIFile { - if let Some(file_metadata) = debug_context(cx).created_files.borrow().get(key) { +fn file_metadata_raw(cx: &CrateContext, + file_name: &str, + directory: &str) + -> DIFile { + let key = (Symbol::intern(file_name), Symbol::intern(directory)); + + if let Some(file_metadata) = debug_context(cx).created_files.borrow().get(&key) { return *file_metadata; } - debug!("file_metadata: file_name: {}, work_dir: {}", file_name, work_dir); + debug!("file_metadata: file_name: {}, directory: {}", file_name, directory); let file_name = CString::new(file_name).unwrap(); - let work_dir = CString::new(work_dir).unwrap(); + let directory = CString::new(directory).unwrap(); + let file_metadata = unsafe { - llvm::LLVMRustDIBuilderCreateFile(DIB(cx), file_name.as_ptr(), - work_dir.as_ptr()) + llvm::LLVMRustDIBuilderCreateFile(DIB(cx), + file_name.as_ptr(), + directory.as_ptr()) }; let mut created_files = debug_context(cx).created_files.borrow_mut(); - created_files.insert(key.to_string(), file_metadata); + created_files.insert(key, file_metadata); file_metadata } @@ -761,25 +765,10 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext, debug_context: &CrateDebugContext, sess: &Session) -> DIDescriptor { - let work_dir = &sess.working_dir; let compile_unit_name = match sess.local_crate_source_file { None => fallback_path(scc), - Some(ref abs_path) => { - if abs_path.is_relative() { - sess.warn("debuginfo: Invalid path to crate's local root source file!"); - fallback_path(scc) - } else { - match abs_path.strip_prefix(work_dir) { - Ok(ref p) if p.is_relative() => { - if p.starts_with(Path::new("./")) { - path2cstr(p) - } else { - path2cstr(&Path::new(".").join(p)) - } - } - _ => fallback_path(scc) - } - } + Some(ref path) => { + CString::new(&path[..]).unwrap() } }; @@ -789,7 +778,8 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext, (option_env!("CFG_VERSION")).expect("CFG_VERSION")); let compile_unit_name = compile_unit_name.as_ptr(); - let work_dir = path2cstr(&work_dir); + + let work_dir = CString::new(&sess.working_dir.0[..]).unwrap(); let producer = CString::new(producer).unwrap(); let flags = "\0"; let split_name = "\0"; @@ -1760,7 +1750,7 @@ pub fn create_global_var_metadata(cx: &CrateContext, let (file_metadata, line_number) = if span != syntax_pos::DUMMY_SP { let loc = span_start(cx, span); - (file_metadata(cx, &loc.file.name, &loc.file.abs_path), loc.line as c_uint) + (file_metadata(cx, &loc.file.name, LOCAL_CRATE), loc.line as c_uint) } else { (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER) }; @@ -1795,9 +1785,10 @@ pub fn create_global_var_metadata(cx: &CrateContext, // Creates an "extension" of an existing DIScope into another file. pub fn extend_scope_to_file(ccx: &CrateContext, scope_metadata: DIScope, - file: &syntax_pos::FileMap) + file: &syntax_pos::FileMap, + defining_crate: CrateNum) -> DILexicalBlock { - let file_metadata = file_metadata(ccx, &file.name, &file.abs_path); + let file_metadata = file_metadata(ccx, &file.name, defining_crate); unsafe { llvm::LLVMRustDIBuilderCreateLexicalBlockFile( DIB(ccx), diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 982ea5ffeb7..ebe42a2b908 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -23,7 +23,7 @@ use self::source_loc::InternalDebugLocation::{self, UnknownLocation}; use llvm; use llvm::{ModuleRef, ContextRef, ValueRef}; use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray, DIFlags}; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{DefId, CrateNum}; use rustc::ty::subst::Substs; use abi::Abi; @@ -42,6 +42,7 @@ use std::ptr; use syntax_pos::{self, Span, Pos}; use syntax::ast; +use syntax::symbol::Symbol; use rustc::ty::layout; pub mod gdb; @@ -67,7 +68,7 @@ const DW_TAG_arg_variable: c_uint = 0x101; pub struct CrateDebugContext<'tcx> { llcontext: ContextRef, builder: DIBuilderRef, - created_files: RefCell>, + created_files: RefCell>, created_enum_disr_types: RefCell>, type_map: RefCell>, @@ -103,7 +104,7 @@ pub enum FunctionDebugContext { } impl FunctionDebugContext { - fn get_ref<'a>(&'a self, span: Span) -> &'a FunctionDebugContextData { + pub fn get_ref<'a>(&'a self, span: Span) -> &'a FunctionDebugContextData { match *self { FunctionDebugContext::RegularContext(ref data) => data, FunctionDebugContext::DebugInfoDisabled => { @@ -128,6 +129,7 @@ impl FunctionDebugContext { pub struct FunctionDebugContextData { fn_metadata: DISubprogram, source_locations_enabled: Cell, + pub defining_crate: CrateNum, } pub enum VariableAccess<'a> { @@ -220,8 +222,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, return FunctionDebugContext::FunctionWithoutDebugInfo; } + let def_id = instance.def_id(); let loc = span_start(cx, span); - let file_metadata = file_metadata(cx, &loc.file.name, &loc.file.abs_path); + let file_metadata = file_metadata(cx, &loc.file.name, def_id.krate); let function_type_metadata = unsafe { let fn_signature = get_function_signature(cx, sig); @@ -229,15 +232,15 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }; // Find the enclosing function, in case this is a closure. - let def_key = cx.tcx().def_key(instance.def_id()); + let def_key = cx.tcx().def_key(def_id); let mut name = def_key.disambiguated_data.data.to_string(); let name_len = name.len(); - let fn_def_id = cx.tcx().closure_base_def_id(instance.def_id()); + let enclosing_fn_def_id = cx.tcx().closure_base_def_id(def_id); // Get_template_parameters() will append a `<...>` clause to the function // name if necessary. - let generics = cx.tcx().generics_of(fn_def_id); + let generics = cx.tcx().generics_of(enclosing_fn_def_id); let substs = instance.substs.truncate_to(cx.tcx(), generics); let template_parameters = get_template_parameters(cx, &generics, @@ -289,6 +292,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let fn_debug_context = FunctionDebugContextData { fn_metadata: fn_metadata, source_locations_enabled: Cell::new(false), + defining_crate: def_id.krate, }; return FunctionDebugContext::RegularContext(fn_debug_context); @@ -438,8 +442,9 @@ pub fn declare_local<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, let cx = bcx.ccx; let file = span_start(cx, span).file; - let filename = file.name.clone(); - let file_metadata = file_metadata(cx, &filename[..], &file.abs_path); + let file_metadata = file_metadata(cx, + &file.name[..], + dbg_context.get_ref(span).defining_crate); let loc = span_start(cx, span); let type_metadata = type_metadata(cx, variable_type, span); diff --git a/src/librustc_trans/debuginfo/namespace.rs b/src/librustc_trans/debuginfo/namespace.rs index 521dd7530be..54a129536d0 100644 --- a/src/librustc_trans/debuginfo/namespace.rs +++ b/src/librustc_trans/debuginfo/namespace.rs @@ -72,7 +72,7 @@ pub fn item_namespace(ccx: &CrateContext, def_id: DefId) -> DIScope { let span = ccx.tcx().def_span(def_id); let (file, line) = if span != DUMMY_SP { let loc = span_start(ccx, span); - (file_metadata(ccx, &loc.file.name, &loc.file.abs_path), loc.line as c_uint) + (file_metadata(ccx, &loc.file.name, def_id.krate), loc.line as c_uint) } else { (unknown_file_metadata(ccx), UNKNOWN_LINE_NUMBER) }; diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index af0e27c8ca3..19a556bf3f0 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -157,7 +157,11 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { if pos < self.scopes[scope_id].file_start_pos || pos >= self.scopes[scope_id].file_end_pos { let cm = self.ccx.sess().codemap(); - debuginfo::extend_scope_to_file(self.ccx, scope_metadata, &cm.lookup_char_pos(pos).file) + let defining_crate = self.debug_context.get_ref(DUMMY_SP).defining_crate; + debuginfo::extend_scope_to_file(self.ccx, + scope_metadata, + &cm.lookup_char_pos(pos).file, + defining_crate) } else { scope_metadata } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index a47d5f9937a..6417270b9c7 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -129,7 +129,7 @@ pub fn run_core(search_paths: SearchPaths, ..config::basic_options().clone() }; - let codemap = Rc::new(codemap::CodeMap::new()); + let codemap = Rc::new(codemap::CodeMap::new(sessopts.file_path_mapping())); let diagnostic_handler = errors::Handler::with_tty_emitter(ColorConfig::Auto, true, false, diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 0dafc4225a3..15dada10c0d 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -26,7 +26,7 @@ use std::fmt::Display; use std::io; use std::io::prelude::*; -use syntax::codemap::CodeMap; +use syntax::codemap::{CodeMap, FilePathMapping}; use syntax::parse::lexer::{self, TokenAndSpan}; use syntax::parse::token; use syntax::parse; @@ -36,8 +36,8 @@ use syntax_pos::Span; pub fn render_with_highlighting(src: &str, class: Option<&str>, id: Option<&str>, extension: Option<&str>) -> String { debug!("highlighting: ================\n{}\n==============", src); - let sess = parse::ParseSess::new(); - let fm = sess.codemap().new_filemap("".to_string(), None, src.to_string()); + let sess = parse::ParseSess::new(FilePathMapping::empty()); + let fm = sess.codemap().new_filemap("".to_string(), src.to_string()); let mut out = Vec::new(); write_header(class, id, &mut out).unwrap(); @@ -58,8 +58,8 @@ pub fn render_with_highlighting(src: &str, class: Option<&str>, id: Option<&str> /// be inserted into an element. C.f., `render_with_highlighting` which includes /// an enclosing `
` block.
 pub fn render_inner_with_highlighting(src: &str) -> io::Result {
-    let sess = parse::ParseSess::new();
-    let fm = sess.codemap().new_filemap("".to_string(), None, src.to_string());
+    let sess = parse::ParseSess::new(FilePathMapping::empty());
+    let fm = sess.codemap().new_filemap("".to_string(), src.to_string());
 
     let mut out = Vec::new();
     let mut classifier = Classifier::new(lexer::StringReader::new(&sess, fm), sess.codemap());
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 5b9ab304db0..5428b0663f3 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -74,7 +74,7 @@ pub fn run(input: &str,
         ..config::basic_options().clone()
     };
 
-    let codemap = Rc::new(CodeMap::new());
+    let codemap = Rc::new(CodeMap::new(sessopts.file_path_mapping()));
     let handler =
         errors::Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(codemap.clone()));
 
@@ -217,7 +217,7 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths,
         }
     }
     let data = Arc::new(Mutex::new(Vec::new()));
-    let codemap = Rc::new(CodeMap::new());
+    let codemap = Rc::new(CodeMap::new(sessopts.file_path_mapping()));
     let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
                                                       Some(codemap.clone()));
     let old = io::set_panic(Some(box Sink(data.clone())));
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index da2d0a33d1a..8a88ec3a672 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -104,32 +104,42 @@ impl FileLoader for RealFileLoader {
 
 pub struct CodeMap {
     pub files: RefCell>>,
-    file_loader: Box
+    file_loader: Box,
+    // This is used to apply the file path remapping as specified via
+    // -Zremap-path-prefix to all FileMaps allocated within this CodeMap.
+    path_mapping: FilePathMapping,
 }
 
 impl CodeMap {
-    pub fn new() -> CodeMap {
+    pub fn new(path_mapping: FilePathMapping) -> CodeMap {
         CodeMap {
             files: RefCell::new(Vec::new()),
-            file_loader: Box::new(RealFileLoader)
+            file_loader: Box::new(RealFileLoader),
+            path_mapping: path_mapping,
         }
     }
 
-    pub fn with_file_loader(file_loader: Box) -> CodeMap {
+    pub fn with_file_loader(file_loader: Box,
+                            path_mapping: FilePathMapping)
+                            -> CodeMap {
         CodeMap {
             files: RefCell::new(Vec::new()),
-            file_loader: file_loader
+            file_loader: file_loader,
+            path_mapping: path_mapping,
         }
     }
 
+    pub fn path_mapping(&self) -> &FilePathMapping {
+        &self.path_mapping
+    }
+
     pub fn file_exists(&self, path: &Path) -> bool {
         self.file_loader.file_exists(path)
     }
 
     pub fn load_file(&self, path: &Path) -> io::Result> {
         let src = self.file_loader.read_file(path)?;
-        let abs_path = self.file_loader.abs_path(path).map(|p| p.to_str().unwrap().to_string());
-        Ok(self.new_filemap(path.to_str().unwrap().to_string(), abs_path, src))
+        Ok(self.new_filemap(path.to_str().unwrap().to_string(), src))
     }
 
     fn next_start_pos(&self) -> usize {
@@ -144,8 +154,7 @@ impl CodeMap {
 
     /// Creates a new filemap without setting its line information. If you don't
     /// intend to set the line information yourself, you should use new_filemap_and_lines.
-    pub fn new_filemap(&self, filename: FileName, abs_path: Option,
-                       mut src: String) -> Rc {
+    pub fn new_filemap(&self, filename: FileName, mut src: String) -> Rc {
         let start_pos = self.next_start_pos();
         let mut files = self.files.borrow_mut();
 
@@ -156,9 +165,11 @@ impl CodeMap {
 
         let end_pos = start_pos + src.len();
 
+        let (filename, was_remapped) = self.path_mapping.map_prefix(filename);
+
         let filemap = Rc::new(FileMap {
             name: filename,
-            abs_path: abs_path,
+            name_was_remapped: was_remapped,
             src: Some(Rc::new(src)),
             start_pos: Pos::from_usize(start_pos),
             end_pos: Pos::from_usize(end_pos),
@@ -172,11 +183,8 @@ impl CodeMap {
     }
 
     /// Creates a new filemap and sets its line information.
-    pub fn new_filemap_and_lines(&self, filename: &str, abs_path: Option<&str>,
-                                 src: &str) -> Rc {
-        let fm = self.new_filemap(filename.to_string(),
-                                  abs_path.map(|s| s.to_owned()),
-                                  src.to_owned());
+    pub fn new_filemap_and_lines(&self, filename: &str, src: &str) -> Rc {
+        let fm = self.new_filemap(filename.to_string(), src.to_owned());
         let mut byte_pos: u32 = fm.start_pos.0;
         for line in src.lines() {
             // register the start of this line
@@ -195,7 +203,7 @@ impl CodeMap {
     /// information for things inlined from other crates.
     pub fn new_imported_filemap(&self,
                                 filename: FileName,
-                                abs_path: Option,
+                                name_was_remapped: bool,
                                 source_len: usize,
                                 mut file_local_lines: Vec,
                                 mut file_local_multibyte_chars: Vec)
@@ -216,7 +224,7 @@ impl CodeMap {
 
         let filemap = Rc::new(FileMap {
             name: filename,
-            abs_path: abs_path,
+            name_was_remapped: name_was_remapped,
             src: None,
             start_pos: start_pos,
             end_pos: end_pos,
@@ -550,6 +558,42 @@ impl CodeMapper for CodeMap {
     }
 }
 
+#[derive(Clone)]
+pub struct FilePathMapping {
+    mapping: Vec<(String, String)>,
+}
+
+impl FilePathMapping {
+    pub fn empty() -> FilePathMapping {
+        FilePathMapping {
+            mapping: vec![]
+        }
+    }
+
+    pub fn new(mapping: Vec<(String, String)>) -> FilePathMapping {
+        FilePathMapping {
+            mapping: mapping
+        }
+    }
+
+    /// Applies any path prefix substitution as defined by the mapping.
+    /// The return value is the remapped path and a boolean indicating whether
+    /// the path was affected by the mapping.
+    pub fn map_prefix(&self, path: String) -> (String, bool) {
+        // NOTE: We are iterating over the mapping entries from last to first
+        //       because entries specified later on the command line should
+        //       take precedence.
+        for &(ref from, ref to) in self.mapping.iter().rev() {
+            if path.starts_with(from) {
+                let mapped = path.replacen(from, to, 1);
+                return (mapped, true);
+            }
+        }
+
+        (path, false)
+    }
+}
+
 // _____________________________________________________________________________
 // Tests
 //
@@ -561,9 +605,8 @@ mod tests {
 
     #[test]
     fn t1 () {
-        let cm = CodeMap::new();
+        let cm = CodeMap::new(FilePathMapping::empty());
         let fm = cm.new_filemap("blork.rs".to_string(),
-                                None,
                                 "first line.\nsecond line".to_string());
         fm.next_line(BytePos(0));
         // Test we can get lines with partial line info.
@@ -578,9 +621,8 @@ mod tests {
     #[test]
     #[should_panic]
     fn t2 () {
-        let cm = CodeMap::new();
+        let cm = CodeMap::new(FilePathMapping::empty());
         let fm = cm.new_filemap("blork.rs".to_string(),
-                                None,
                                 "first line.\nsecond line".to_string());
         // TESTING *REALLY* BROKEN BEHAVIOR:
         fm.next_line(BytePos(0));
@@ -589,15 +631,12 @@ mod tests {
     }
 
     fn init_code_map() -> CodeMap {
-        let cm = CodeMap::new();
+        let cm = CodeMap::new(FilePathMapping::empty());
         let fm1 = cm.new_filemap("blork.rs".to_string(),
-                                 None,
                                  "first line.\nsecond line".to_string());
         let fm2 = cm.new_filemap("empty.rs".to_string(),
-                                 None,
                                  "".to_string());
         let fm3 = cm.new_filemap("blork2.rs".to_string(),
-                                 None,
                                  "first line.\nsecond line".to_string());
 
         fm1.next_line(BytePos(0));
@@ -656,14 +695,12 @@ mod tests {
     }
 
     fn init_code_map_mbc() -> CodeMap {
-        let cm = CodeMap::new();
+        let cm = CodeMap::new(FilePathMapping::empty());
         // € is a three byte utf8 char.
         let fm1 =
             cm.new_filemap("blork.rs".to_string(),
-                           None,
                            "fir€st €€€€ line.\nsecond line".to_string());
         let fm2 = cm.new_filemap("blork2.rs".to_string(),
-                                 None,
                                  "first line€€.\n€ second line".to_string());
 
         fm1.next_line(BytePos(0));
@@ -728,10 +765,10 @@ mod tests {
     /// lines in the middle of a file.
     #[test]
     fn span_to_snippet_and_lines_spanning_multiple_lines() {
-        let cm = CodeMap::new();
+        let cm = CodeMap::new(FilePathMapping::empty());
         let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
         let selection = "     \n    ~~\n~~~\n~~~~~     \n   \n";
-        cm.new_filemap_and_lines("blork.rs", None, inputtext);
+        cm.new_filemap_and_lines("blork.rs", inputtext);
         let span = span_from_selection(inputtext, selection);
 
         // check that we are extracting the text we thought we were extracting
@@ -770,11 +807,11 @@ mod tests {
     /// Test failing to merge two spans on different lines
     #[test]
     fn span_merging_fail() {
-        let cm = CodeMap::new();
+        let cm = CodeMap::new(FilePathMapping::empty());
         let inputtext  = "bbbb BB\ncc CCC\n";
         let selection1 = "     ~~\n      \n";
         let selection2 = "       \n   ~~~\n";
-        cm.new_filemap_and_lines("blork.rs", None, inputtext);
+        cm.new_filemap_and_lines("blork.rs", inputtext);
         let span1 = span_from_selection(inputtext, selection1);
         let span2 = span_from_selection(inputtext, selection2);
 
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 842398ea02b..2db295d0136 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -783,7 +783,7 @@ fn stream_for_item(item: &Annotatable, parse_sess: &ParseSess) -> TokenStream {
 
 fn string_to_stream(text: String, parse_sess: &ParseSess) -> TokenStream {
     let filename = String::from("");
-    filemap_to_stream(parse_sess, parse_sess.codemap().new_filemap(filename, None, text))
+    filemap_to_stream(parse_sess, parse_sess.codemap().new_filemap(filename, text))
 }
 
 impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index 0103d6ea959..22a5776315a 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -142,7 +142,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenT
             // Add this input file to the code map to make it available as
             // dependency information
             let filename = format!("{}", file.display());
-            cx.codemap().new_filemap_and_lines(&filename, None, &src);
+            cx.codemap().new_filemap_and_lines(&filename, &src);
 
             base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&src)))
         }
@@ -173,7 +173,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::Toke
             // Add this input file to the code map to make it available as
             // dependency information, but don't enter it's contents
             let filename = format!("{}", file.display());
-            cx.codemap().new_filemap_and_lines(&filename, None, "");
+            cx.codemap().new_filemap_and_lines(&filename, "");
 
             base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Rc::new(bytes))))
         }
diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs
index dec1b7d1d87..47b60f0e080 100644
--- a/src/libsyntax/json.rs
+++ b/src/libsyntax/json.rs
@@ -19,7 +19,7 @@
 
 // FIXME spec the JSON output properly.
 
-use codemap::CodeMap;
+use codemap::{CodeMap, FilePathMapping};
 use syntax_pos::{self, MacroBacktrace, Span, SpanLabel, MultiSpan};
 use errors::registry::Registry;
 use errors::{DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion, CodeMapper};
@@ -48,7 +48,8 @@ impl JsonEmitter {
     }
 
     pub fn basic() -> JsonEmitter {
-        JsonEmitter::stderr(None, Rc::new(CodeMap::new()))
+        let file_path_mapping = FilePathMapping::empty();
+        JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)))
     }
 
     pub fn new(dst: Box,
diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs
index c97b8ddf919..7ac322b144c 100644
--- a/src/libsyntax/parse/lexer/comments.rs
+++ b/src/libsyntax/parse/lexer/comments.rs
@@ -348,8 +348,8 @@ pub fn gather_comments_and_literals(sess: &ParseSess, path: String, srdr: &mut R
     let mut src = Vec::new();
     srdr.read_to_end(&mut src).unwrap();
     let src = String::from_utf8(src).unwrap();
-    let cm = CodeMap::new();
-    let filemap = cm.new_filemap(path, None, src);
+    let cm = CodeMap::new(sess.codemap().path_mapping().clone());
+    let filemap = cm.new_filemap(path, src);
     let mut rdr = lexer::StringReader::new_raw(sess, filemap);
 
     let mut comments: Vec = Vec::new();
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 920b2c401e2..c2e5763237d 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -10,7 +10,7 @@
 
 use ast::{self, Ident};
 use syntax_pos::{self, BytePos, CharPos, Pos, Span, NO_EXPANSION};
-use codemap::CodeMap;
+use codemap::{CodeMap, FilePathMapping};
 use errors::{FatalError, DiagnosticBuilder};
 use parse::{token, ParseSess};
 use str::char_at;
@@ -563,7 +563,7 @@ impl<'a> StringReader<'a> {
 
                 // I guess this is the only way to figure out if
                 // we're at the beginning of the file...
-                let cmap = CodeMap::new();
+                let cmap = CodeMap::new(FilePathMapping::empty());
                 cmap.files.borrow_mut().push(self.filemap.clone());
                 let loc = cmap.lookup_char_pos_adj(self.pos);
                 debug!("Skipping a shebang");
@@ -1718,13 +1718,13 @@ mod tests {
                  sess: &'a ParseSess,
                  teststr: String)
                  -> StringReader<'a> {
-        let fm = cm.new_filemap("zebra.rs".to_string(), None, teststr);
+        let fm = cm.new_filemap("zebra.rs".to_string(), teststr);
         StringReader::new(sess, fm)
     }
 
     #[test]
     fn t1() {
-        let cm = Rc::new(CodeMap::new());
+        let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
         let sh = mk_sess(cm.clone());
         let mut string_reader = setup(&cm,
                                       &sh,
@@ -1776,7 +1776,7 @@ mod tests {
 
     #[test]
     fn doublecolonparsing() {
-        let cm = Rc::new(CodeMap::new());
+        let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
         let sh = mk_sess(cm.clone());
         check_tokenization(setup(&cm, &sh, "a b".to_string()),
                            vec![mk_ident("a"), token::Whitespace, mk_ident("b")]);
@@ -1784,7 +1784,7 @@ mod tests {
 
     #[test]
     fn dcparsing_2() {
-        let cm = Rc::new(CodeMap::new());
+        let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
         let sh = mk_sess(cm.clone());
         check_tokenization(setup(&cm, &sh, "a::b".to_string()),
                            vec![mk_ident("a"), token::ModSep, mk_ident("b")]);
@@ -1792,7 +1792,7 @@ mod tests {
 
     #[test]
     fn dcparsing_3() {
-        let cm = Rc::new(CodeMap::new());
+        let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
         let sh = mk_sess(cm.clone());
         check_tokenization(setup(&cm, &sh, "a ::b".to_string()),
                            vec![mk_ident("a"), token::Whitespace, token::ModSep, mk_ident("b")]);
@@ -1800,7 +1800,7 @@ mod tests {
 
     #[test]
     fn dcparsing_4() {
-        let cm = Rc::new(CodeMap::new());
+        let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
         let sh = mk_sess(cm.clone());
         check_tokenization(setup(&cm, &sh, "a:: b".to_string()),
                            vec![mk_ident("a"), token::ModSep, token::Whitespace, mk_ident("b")]);
@@ -1808,7 +1808,7 @@ mod tests {
 
     #[test]
     fn character_a() {
-        let cm = Rc::new(CodeMap::new());
+        let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
         let sh = mk_sess(cm.clone());
         assert_eq!(setup(&cm, &sh, "'a'".to_string()).next_token().tok,
                    token::Literal(token::Char(Symbol::intern("a")), None));
@@ -1816,7 +1816,7 @@ mod tests {
 
     #[test]
     fn character_space() {
-        let cm = Rc::new(CodeMap::new());
+        let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
         let sh = mk_sess(cm.clone());
         assert_eq!(setup(&cm, &sh, "' '".to_string()).next_token().tok,
                    token::Literal(token::Char(Symbol::intern(" ")), None));
@@ -1824,7 +1824,7 @@ mod tests {
 
     #[test]
     fn character_escaped() {
-        let cm = Rc::new(CodeMap::new());
+        let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
         let sh = mk_sess(cm.clone());
         assert_eq!(setup(&cm, &sh, "'\\n'".to_string()).next_token().tok,
                    token::Literal(token::Char(Symbol::intern("\\n")), None));
@@ -1832,7 +1832,7 @@ mod tests {
 
     #[test]
     fn lifetime_name() {
-        let cm = Rc::new(CodeMap::new());
+        let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
         let sh = mk_sess(cm.clone());
         assert_eq!(setup(&cm, &sh, "'abc".to_string()).next_token().tok,
                    token::Lifetime(Ident::from_str("'abc")));
@@ -1840,7 +1840,7 @@ mod tests {
 
     #[test]
     fn raw_string() {
-        let cm = Rc::new(CodeMap::new());
+        let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
         let sh = mk_sess(cm.clone());
         assert_eq!(setup(&cm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string())
                        .next_token()
@@ -1850,7 +1850,7 @@ mod tests {
 
     #[test]
     fn literal_suffixes() {
-        let cm = Rc::new(CodeMap::new());
+        let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
         let sh = mk_sess(cm.clone());
         macro_rules! test {
             ($input: expr, $tok_type: ident, $tok_contents: expr) => {{
@@ -1894,7 +1894,7 @@ mod tests {
 
     #[test]
     fn nested_block_comments() {
-        let cm = Rc::new(CodeMap::new());
+        let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
         let sh = mk_sess(cm.clone());
         let mut lexer = setup(&cm, &sh, "/* /* */ */'a'".to_string());
         match lexer.next_token().tok {
@@ -1907,7 +1907,7 @@ mod tests {
 
     #[test]
     fn crlf_comments() {
-        let cm = Rc::new(CodeMap::new());
+        let cm = Rc::new(CodeMap::new(FilePathMapping::empty()));
         let sh = mk_sess(cm.clone());
         let mut lexer = setup(&cm, &sh, "// test\r\n/// test\r\n".to_string());
         let comment = lexer.next_token();
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index c63a6524f74..9d8f3b3d039 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -11,7 +11,7 @@
 //! The main parser interface
 
 use ast::{self, CrateConfig};
-use codemap::CodeMap;
+use codemap::{CodeMap, FilePathMapping};
 use syntax_pos::{self, Span, FileMap, NO_EXPANSION};
 use errors::{Handler, ColorConfig, DiagnosticBuilder};
 use feature_gate::UnstableFeatures;
@@ -53,8 +53,8 @@ pub struct ParseSess {
 }
 
 impl ParseSess {
-    pub fn new() -> Self {
-        let cm = Rc::new(CodeMap::new());
+    pub fn new(file_path_mapping: FilePathMapping) -> Self {
+        let cm = Rc::new(CodeMap::new(file_path_mapping));
         let handler = Handler::with_tty_emitter(ColorConfig::Auto,
                                                 true,
                                                 false,
@@ -143,13 +143,13 @@ pub fn parse_stmt_from_source_str<'a>(name: String, source: String, sess: &'a Pa
 
 pub fn parse_stream_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess)
                                         -> TokenStream {
-    filemap_to_stream(sess, sess.codemap().new_filemap(name, None, source))
+    filemap_to_stream(sess, sess.codemap().new_filemap(name, source))
 }
 
 // Create a new parser from a source string
 pub fn new_parser_from_source_str<'a>(sess: &'a ParseSess, name: String, source: String)
                                       -> Parser<'a> {
-    filemap_to_parser(sess, sess.codemap().new_filemap(name, None, source))
+    filemap_to_parser(sess, sess.codemap().new_filemap(name, source))
 }
 
 /// Create a new parser, handling errors as appropriate
@@ -828,7 +828,7 @@ mod tests {
     }
 
     #[test] fn parse_ident_pat () {
-        let sess = ParseSess::new();
+        let sess = ParseSess::new(FilePathMapping::empty());
         let mut parser = string_to_parser(&sess, "b".to_string());
         assert!(panictry!(parser.parse_pat())
                 == P(ast::Pat{
@@ -998,7 +998,7 @@ mod tests {
     }
 
     #[test] fn crlf_doc_comments() {
-        let sess = ParseSess::new();
+        let sess = ParseSess::new(FilePathMapping::empty());
 
         let name = "".to_string();
         let source = "/// doc comment\r\nfn foo() {}".to_string();
@@ -1023,7 +1023,7 @@ mod tests {
 
     #[test]
     fn ttdelim_span() {
-        let sess = ParseSess::new();
+        let sess = ParseSess::new(FilePathMapping::empty());
         let expr = parse::parse_expr_from_source_str("foo".to_string(),
             "foo!( fn main() { body } )".to_string(), &sess).unwrap();
 
diff --git a/src/libsyntax/test_snippet.rs b/src/libsyntax/test_snippet.rs
index dc9b22c37e2..b3fa1e97376 100644
--- a/src/libsyntax/test_snippet.rs
+++ b/src/libsyntax/test_snippet.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use codemap::CodeMap;
+use codemap::{CodeMap, FilePathMapping};
 use errors::Handler;
 use errors::emitter::EmitterWriter;
 use std::io;
@@ -47,8 +47,8 @@ impl Write for Shared {
 fn test_harness(file_text: &str, span_labels: Vec, expected_output: &str) {
     let output = Arc::new(Mutex::new(Vec::new()));
 
-    let code_map = Rc::new(CodeMap::new());
-    code_map.new_filemap_and_lines("test.rs", None, &file_text);
+    let code_map = Rc::new(CodeMap::new(FilePathMapping::empty()));
+    code_map.new_filemap_and_lines("test.rs", &file_text);
 
     let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end);
     let mut msp = MultiSpan::from_span(primary_span);
diff --git a/src/libsyntax/util/parser_testing.rs b/src/libsyntax/util/parser_testing.rs
index 51eb295b502..2727ab79ebf 100644
--- a/src/libsyntax/util/parser_testing.rs
+++ b/src/libsyntax/util/parser_testing.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 use ast::{self, Ident};
+use codemap::FilePathMapping;
 use parse::{ParseSess, PResult, filemap_to_stream};
 use parse::{lexer, new_parser_from_source_str};
 use parse::parser::Parser;
@@ -18,8 +19,8 @@ use std::iter::Peekable;
 
 /// Map a string to tts, using a made-up filename:
 pub fn string_to_stream(source_str: String) -> TokenStream {
-    let ps = ParseSess::new();
-    filemap_to_stream(&ps, ps.codemap().new_filemap("bogofile".to_string(), None, source_str))
+    let ps = ParseSess::new(FilePathMapping::empty());
+    filemap_to_stream(&ps, ps.codemap().new_filemap("bogofile".to_string(), source_str))
 }
 
 /// Map string to parser (via tts)
@@ -38,7 +39,7 @@ fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> T
 
 /// Parse a string, return a crate.
 pub fn string_to_crate (source_str : String) -> ast::Crate {
-    let ps = ParseSess::new();
+    let ps = ParseSess::new(FilePathMapping::empty());
     with_error_checking_parse(source_str, &ps, |p| {
         p.parse_crate_mod()
     })
@@ -46,7 +47,7 @@ pub fn string_to_crate (source_str : String) -> ast::Crate {
 
 /// Parse a string, return an expr
 pub fn string_to_expr (source_str : String) -> P {
-    let ps = ParseSess::new();
+    let ps = ParseSess::new(FilePathMapping::empty());
     with_error_checking_parse(source_str, &ps, |p| {
         p.parse_expr()
     })
@@ -54,7 +55,7 @@ pub fn string_to_expr (source_str : String) -> P {
 
 /// Parse a string, return an item
 pub fn string_to_item (source_str : String) -> Option> {
-    let ps = ParseSess::new();
+    let ps = ParseSess::new(FilePathMapping::empty());
     with_error_checking_parse(source_str, &ps, |p| {
         p.parse_item()
     })
@@ -62,7 +63,7 @@ pub fn string_to_item (source_str : String) -> Option> {
 
 /// Parse a string, return a stmt
 pub fn string_to_stmt(source_str : String) -> Option {
-    let ps = ParseSess::new();
+    let ps = ParseSess::new(FilePathMapping::empty());
     with_error_checking_parse(source_str, &ps, |p| {
         p.parse_stmt()
     })
@@ -71,7 +72,7 @@ pub fn string_to_stmt(source_str : String) -> Option {
 /// Parse a string, return a pat. Uses "irrefutable"... which doesn't
 /// (currently) affect parsing.
 pub fn string_to_pat(source_str: String) -> P {
-    let ps = ParseSess::new();
+    let ps = ParseSess::new(FilePathMapping::empty());
     with_error_checking_parse(source_str, &ps, |p| {
         p.parse_pat()
     })
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index aaafcadc38a..f46b4fcb715 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -369,13 +369,14 @@ pub struct MultiByteChar {
 }
 
 /// A single source in the CodeMap.
+#[derive(Clone)]
 pub struct FileMap {
     /// The name of the file that the source came from, source that doesn't
     /// originate from files has names between angle brackets by convention,
     /// e.g. ``
     pub name: FileName,
-    /// The absolute path of the file that the source came from.
-    pub abs_path: Option,
+    /// True if the `name` field above has been modified by -Zremap-path-prefix
+    pub name_was_remapped: bool,
     /// The complete source code
     pub src: Option>,
     /// The start position of this source in the CodeMap
@@ -392,7 +393,7 @@ impl Encodable for FileMap {
     fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_struct("FileMap", 6, |s| {
             s.emit_struct_field("name", 0, |s| self.name.encode(s))?;
-            s.emit_struct_field("abs_path", 1, |s| self.abs_path.encode(s))?;
+            s.emit_struct_field("name_was_remapped", 1, |s| self.name_was_remapped.encode(s))?;
             s.emit_struct_field("start_pos", 2, |s| self.start_pos.encode(s))?;
             s.emit_struct_field("end_pos", 3, |s| self.end_pos.encode(s))?;
             s.emit_struct_field("lines", 4, |s| {
@@ -453,8 +454,8 @@ impl Decodable for FileMap {
 
         d.read_struct("FileMap", 6, |d| {
             let name: String = d.read_struct_field("name", 0, |d| Decodable::decode(d))?;
-            let abs_path: Option =
-                d.read_struct_field("abs_path", 1, |d| Decodable::decode(d))?;
+            let name_was_remapped: bool =
+                d.read_struct_field("name_was_remapped", 1, |d| Decodable::decode(d))?;
             let start_pos: BytePos = d.read_struct_field("start_pos", 2, |d| Decodable::decode(d))?;
             let end_pos: BytePos = d.read_struct_field("end_pos", 3, |d| Decodable::decode(d))?;
             let lines: Vec = d.read_struct_field("lines", 4, |d| {
@@ -489,7 +490,7 @@ impl Decodable for FileMap {
                 d.read_struct_field("multibyte_chars", 5, |d| Decodable::decode(d))?;
             Ok(FileMap {
                 name: name,
-                abs_path: abs_path,
+                name_was_remapped: name_was_remapped,
                 start_pos: start_pos,
                 end_pos: end_pos,
                 src: None,
diff --git a/src/test/codegen/remap_path_prefix.rs b/src/test/codegen/remap_path_prefix.rs
new file mode 100644
index 00000000000..98e8180ed38
--- /dev/null
+++ b/src/test/codegen/remap_path_prefix.rs
@@ -0,0 +1,19 @@
+// Copyright 2017 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.
+
+// ignore-tidy-linelength
+
+// compile-flags: -g -Zremap-path-prefix-from={{cwd}} -Zremap-path-prefix-to=/the/cwd -Zremap-path-prefix-from={{src-base}} -Zremap-path-prefix-to=/the/src
+
+// CHECK: !DIFile(filename: "/the/src/remap_path_prefix.rs", directory: "/the/cwd")
+
+fn main() {
+    // We just check that the DIFile got remapped properly.
+}
diff --git a/src/test/compile-fail-fulldeps/qquote.rs b/src/test/compile-fail-fulldeps/qquote.rs
index 272bf1150ca..3e2829adeb5 100644
--- a/src/test/compile-fail-fulldeps/qquote.rs
+++ b/src/test/compile-fail-fulldeps/qquote.rs
@@ -16,12 +16,13 @@ extern crate syntax;
 extern crate syntax_pos;
 
 use syntax::ast;
+use syntax::codemap::FilePathMapping;
 use syntax::print::pprust;
 use syntax::symbol::Symbol;
 use syntax_pos::DUMMY_SP;
 
 fn main() {
-    let ps = syntax::parse::ParseSess::new();
+    let ps = syntax::parse::ParseSess::new(FilePathMapping::empty());
     let mut resolver = syntax::ext::base::DummyResolver;
     let mut cx = syntax::ext::base::ExtCtxt::new(
         &ps,
diff --git a/src/test/run-fail-fulldeps/qquote.rs b/src/test/run-fail-fulldeps/qquote.rs
index 5518ab47c2b..27b9e27be43 100644
--- a/src/test/run-fail-fulldeps/qquote.rs
+++ b/src/test/run-fail-fulldeps/qquote.rs
@@ -24,7 +24,7 @@ use syntax::symbol::Symbol;
 use syntax_pos::DUMMY_SP;
 
 fn main() {
-    let ps = syntax::parse::ParseSess::new();
+    let ps = syntax::parse::ParseSess::new(codemap::FilePathMapping::empty());
     let mut resolver = syntax::ext::base::DummyResolver;
     let mut cx = syntax::ext::base::ExtCtxt::new(
         &ps,
diff --git a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs
index 5139b68bce7..fc031f4a310 100644
--- a/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs
+++ b/src/test/run-pass-fulldeps/ast_stmt_expr_attr.rs
@@ -17,6 +17,7 @@ extern crate syntax;
 use syntax::ast::*;
 use syntax::attr::*;
 use syntax::ast;
+use syntax::codemap::FilePathMapping;
 use syntax::parse;
 use syntax::parse::{ParseSess, PResult};
 use syntax::parse::new_parser_from_source_str;
@@ -78,7 +79,7 @@ fn str_compare String>(e: &str, expected: &[T], actual: &[T], f:
 }
 
 fn check_expr_attrs(es: &str, expected: &[&str]) {
-    let ps = ParseSess::new();
+    let ps = ParseSess::new(FilePathMapping::empty());
     let e = expr(es, &ps).expect("parse error");
     let actual = &e.attrs;
     str_compare(es,
@@ -88,7 +89,7 @@ fn check_expr_attrs(es: &str, expected: &[&str]) {
 }
 
 fn check_stmt_attrs(es: &str, expected: &[&str]) {
-    let ps = ParseSess::new();
+    let ps = ParseSess::new(FilePathMapping::empty());
     let e = stmt(es, &ps).expect("parse error");
     let actual = e.node.attrs();
     str_compare(es,
@@ -98,7 +99,7 @@ fn check_stmt_attrs(es: &str, expected: &[&str]) {
 }
 
 fn reject_expr_parse(es: &str) {
-    let ps = ParseSess::new();
+    let ps = ParseSess::new(FilePathMapping::empty());
     match expr(es, &ps) {
         Ok(_) => panic!("parser did not reject `{}`", es),
         Err(mut e) => e.cancel(),
@@ -106,7 +107,7 @@ fn reject_expr_parse(es: &str) {
 }
 
 fn reject_stmt_parse(es: &str) {
-    let ps = ParseSess::new();
+    let ps = ParseSess::new(FilePathMapping::empty());
     match stmt(es, &ps) {
         Ok(_) => panic!("parser did not reject `{}`", es),
         Err(mut e) => e.cancel(),
diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs
index 4a8246ec429..949aa8a9518 100644
--- a/src/test/run-pass-fulldeps/qquote.rs
+++ b/src/test/run-pass-fulldeps/qquote.rs
@@ -15,12 +15,13 @@
 extern crate syntax;
 extern crate syntax_pos;
 
+use syntax::codemap::FilePathMapping;
 use syntax::print::pprust::*;
 use syntax::symbol::Symbol;
 use syntax_pos::DUMMY_SP;
 
 fn main() {
-    let ps = syntax::parse::ParseSess::new();
+    let ps = syntax::parse::ParseSess::new(FilePathMapping::empty());
     let mut resolver = syntax::ext::base::DummyResolver;
     let mut cx = syntax::ext::base::ExtCtxt::new(
         &ps,
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 522cd222c26..0f653dfbcf0 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -40,23 +40,24 @@ impl EarlyProps {
                     None,
                     &mut |ln| {
             props.ignore =
-                props.ignore || parse_name_directive(ln, "ignore-test") ||
-                parse_name_directive(ln, &ignore_target(config)) ||
-                parse_name_directive(ln, &ignore_architecture(config)) ||
-                parse_name_directive(ln, &ignore_stage(config)) ||
-                parse_name_directive(ln, &ignore_env(config)) ||
-                (config.mode == common::Pretty && parse_name_directive(ln, "ignore-pretty")) ||
+                props.ignore || config.parse_name_directive(ln, "ignore-test") ||
+                config.parse_name_directive(ln, &ignore_target(config)) ||
+                config.parse_name_directive(ln, &ignore_architecture(config)) ||
+                config.parse_name_directive(ln, &ignore_stage(config)) ||
+                config.parse_name_directive(ln, &ignore_env(config)) ||
+                (config.mode == common::Pretty &&
+                 config.parse_name_directive(ln, "ignore-pretty")) ||
                 (config.target != config.host &&
-                 parse_name_directive(ln, "ignore-cross-compile")) ||
+                 config.parse_name_directive(ln, "ignore-cross-compile")) ||
                 ignore_gdb(config, ln) ||
                 ignore_lldb(config, ln) ||
                 ignore_llvm(config, ln);
 
-            if let Some(s) = parse_aux_build(ln) {
+            if let Some(s) = config.parse_aux_build(ln) {
                 props.aux.push(s);
             }
 
-            props.should_fail = props.should_fail || parse_name_directive(ln, "should-fail");
+            props.should_fail = props.should_fail || config.parse_name_directive(ln, "should-fail");
         });
 
         return props;
@@ -80,7 +81,7 @@ impl EarlyProps {
             }
 
             if !line.contains("ignore-gdb-version") &&
-               parse_name_directive(line, "ignore-gdb") {
+               config.parse_name_directive(line, "ignore-gdb") {
                 return true;
             }
 
@@ -143,7 +144,7 @@ impl EarlyProps {
                 return false;
             }
 
-            if parse_name_directive(line, "ignore-lldb") {
+            if config.parse_name_directive(line, "ignore-lldb") {
                 return true;
             }
 
@@ -260,19 +261,23 @@ impl TestProps {
         }
     }
 
-    pub fn from_aux_file(&self, testfile: &Path, cfg: Option<&str>) -> Self {
+    pub fn from_aux_file(&self,
+                         testfile: &Path,
+                         cfg: Option<&str>,
+                         config: &Config)
+                         -> Self {
         let mut props = TestProps::new();
 
         // copy over select properties to the aux build:
         props.incremental_dir = self.incremental_dir.clone();
-        props.load_from(testfile, cfg);
+        props.load_from(testfile, cfg, config);
 
         props
     }
 
-    pub fn from_file(testfile: &Path) -> Self {
+    pub fn from_file(testfile: &Path, config: &Config) -> Self {
         let mut props = TestProps::new();
-        props.load_from(testfile, None);
+        props.load_from(testfile, None, config);
         props
     }
 
@@ -280,85 +285,88 @@ impl TestProps {
     /// tied to a particular revision `foo` (indicated by writing
     /// `//[foo]`), then the property is ignored unless `cfg` is
     /// `Some("foo")`.
-    pub fn load_from(&mut self, testfile: &Path, cfg: Option<&str>) {
+    pub fn load_from(&mut self,
+                     testfile: &Path,
+                     cfg: Option<&str>,
+                     config: &Config) {
         iter_header(testfile,
                     cfg,
                     &mut |ln| {
-            if let Some(ep) = parse_error_pattern(ln) {
+            if let Some(ep) = config.parse_error_pattern(ln) {
                 self.error_patterns.push(ep);
             }
 
-            if let Some(flags) = parse_compile_flags(ln) {
+            if let Some(flags) = config.parse_compile_flags(ln) {
                 self.compile_flags.extend(flags.split_whitespace()
                     .map(|s| s.to_owned()));
             }
 
-            if let Some(r) = parse_revisions(ln) {
+            if let Some(r) = config.parse_revisions(ln) {
                 self.revisions.extend(r);
             }
 
             if self.run_flags.is_none() {
-                self.run_flags = parse_run_flags(ln);
+                self.run_flags = config.parse_run_flags(ln);
             }
 
             if self.pp_exact.is_none() {
-                self.pp_exact = parse_pp_exact(ln, testfile);
+                self.pp_exact = config.parse_pp_exact(ln, testfile);
             }
 
             if !self.build_aux_docs {
-                self.build_aux_docs = parse_build_aux_docs(ln);
+                self.build_aux_docs = config.parse_build_aux_docs(ln);
             }
 
             if !self.force_host {
-                self.force_host = parse_force_host(ln);
+                self.force_host = config.parse_force_host(ln);
             }
 
             if !self.check_stdout {
-                self.check_stdout = parse_check_stdout(ln);
+                self.check_stdout = config.parse_check_stdout(ln);
             }
 
             if !self.no_prefer_dynamic {
-                self.no_prefer_dynamic = parse_no_prefer_dynamic(ln);
+                self.no_prefer_dynamic = config.parse_no_prefer_dynamic(ln);
             }
 
             if !self.pretty_expanded {
-                self.pretty_expanded = parse_pretty_expanded(ln);
+                self.pretty_expanded = config.parse_pretty_expanded(ln);
             }
 
-            if let Some(m) = parse_pretty_mode(ln) {
+            if let Some(m) = config.parse_pretty_mode(ln) {
                 self.pretty_mode = m;
             }
 
             if !self.pretty_compare_only {
-                self.pretty_compare_only = parse_pretty_compare_only(ln);
+                self.pretty_compare_only = config.parse_pretty_compare_only(ln);
             }
 
-            if let Some(ab) = parse_aux_build(ln) {
+            if let Some(ab) = config.parse_aux_build(ln) {
                 self.aux_builds.push(ab);
             }
 
-            if let Some(ee) = parse_env(ln, "exec-env") {
+            if let Some(ee) = config.parse_env(ln, "exec-env") {
                 self.exec_env.push(ee);
             }
 
-            if let Some(ee) = parse_env(ln, "rustc-env") {
+            if let Some(ee) = config.parse_env(ln, "rustc-env") {
                 self.rustc_env.push(ee);
             }
 
-            if let Some(cl) = parse_check_line(ln) {
+            if let Some(cl) = config.parse_check_line(ln) {
                 self.check_lines.push(cl);
             }
 
-            if let Some(of) = parse_forbid_output(ln) {
+            if let Some(of) = config.parse_forbid_output(ln) {
                 self.forbid_output.push(of);
             }
 
             if !self.must_compile_successfully {
-                self.must_compile_successfully = parse_must_compile_successfully(ln);
+                self.must_compile_successfully = config.parse_must_compile_successfully(ln);
             }
 
             if !self.check_test_line_numbers_match {
-                self.check_test_line_numbers_match = parse_check_test_line_numbers_match(ln);
+                self.check_test_line_numbers_match = config.parse_check_test_line_numbers_match(ln);
             }
         });
 
@@ -410,114 +418,118 @@ fn iter_header(testfile: &Path, cfg: Option<&str>, it: &mut FnMut(&str)) {
     return;
 }
 
-fn parse_error_pattern(line: &str) -> Option {
-    parse_name_value_directive(line, "error-pattern")
-}
+impl Config {
 
-fn parse_forbid_output(line: &str) -> Option {
-    parse_name_value_directive(line, "forbid-output")
-}
+    fn parse_error_pattern(&self, line: &str) -> Option {
+        self.parse_name_value_directive(line, "error-pattern")
+    }
 
-fn parse_aux_build(line: &str) -> Option {
-    parse_name_value_directive(line, "aux-build")
-}
+    fn parse_forbid_output(&self, line: &str) -> Option {
+        self.parse_name_value_directive(line, "forbid-output")
+    }
 
-fn parse_compile_flags(line: &str) -> Option {
-    parse_name_value_directive(line, "compile-flags")
-}
+    fn parse_aux_build(&self, line: &str) -> Option {
+        self.parse_name_value_directive(line, "aux-build")
+    }
 
-fn parse_revisions(line: &str) -> Option> {
-    parse_name_value_directive(line, "revisions")
-        .map(|r| r.split_whitespace().map(|t| t.to_string()).collect())
-}
+    fn parse_compile_flags(&self, line: &str) -> Option {
+        self.parse_name_value_directive(line, "compile-flags")
+    }
 
-fn parse_run_flags(line: &str) -> Option {
-    parse_name_value_directive(line, "run-flags")
-}
+    fn parse_revisions(&self, line: &str) -> Option> {
+        self.parse_name_value_directive(line, "revisions")
+            .map(|r| r.split_whitespace().map(|t| t.to_string()).collect())
+    }
 
-fn parse_check_line(line: &str) -> Option {
-    parse_name_value_directive(line, "check")
-}
+    fn parse_run_flags(&self, line: &str) -> Option {
+        self.parse_name_value_directive(line, "run-flags")
+    }
 
-fn parse_force_host(line: &str) -> bool {
-    parse_name_directive(line, "force-host")
-}
+    fn parse_check_line(&self, line: &str) -> Option {
+        self.parse_name_value_directive(line, "check")
+    }
 
-fn parse_build_aux_docs(line: &str) -> bool {
-    parse_name_directive(line, "build-aux-docs")
-}
+    fn parse_force_host(&self, line: &str) -> bool {
+        self.parse_name_directive(line, "force-host")
+    }
 
-fn parse_check_stdout(line: &str) -> bool {
-    parse_name_directive(line, "check-stdout")
-}
+    fn parse_build_aux_docs(&self, line: &str) -> bool {
+        self.parse_name_directive(line, "build-aux-docs")
+    }
 
-fn parse_no_prefer_dynamic(line: &str) -> bool {
-    parse_name_directive(line, "no-prefer-dynamic")
-}
+    fn parse_check_stdout(&self, line: &str) -> bool {
+        self.parse_name_directive(line, "check-stdout")
+    }
 
-fn parse_pretty_expanded(line: &str) -> bool {
-    parse_name_directive(line, "pretty-expanded")
-}
+    fn parse_no_prefer_dynamic(&self, line: &str) -> bool {
+        self.parse_name_directive(line, "no-prefer-dynamic")
+    }
 
-fn parse_pretty_mode(line: &str) -> Option {
-    parse_name_value_directive(line, "pretty-mode")
-}
+    fn parse_pretty_expanded(&self, line: &str) -> bool {
+        self.parse_name_directive(line, "pretty-expanded")
+    }
 
-fn parse_pretty_compare_only(line: &str) -> bool {
-    parse_name_directive(line, "pretty-compare-only")
-}
+    fn parse_pretty_mode(&self, line: &str) -> Option {
+        self.parse_name_value_directive(line, "pretty-mode")
+    }
 
-fn parse_must_compile_successfully(line: &str) -> bool {
-    parse_name_directive(line, "must-compile-successfully")
-}
+    fn parse_pretty_compare_only(&self, line: &str) -> bool {
+        self.parse_name_directive(line, "pretty-compare-only")
+    }
 
-fn parse_check_test_line_numbers_match(line: &str) -> bool {
-    parse_name_directive(line, "check-test-line-numbers-match")
-}
+    fn parse_must_compile_successfully(&self, line: &str) -> bool {
+        self.parse_name_directive(line, "must-compile-successfully")
+    }
 
-fn parse_env(line: &str, name: &str) -> Option<(String, String)> {
-    parse_name_value_directive(line, name).map(|nv| {
-        // nv is either FOO or FOO=BAR
-        let mut strs: Vec = nv.splitn(2, '=')
-            .map(str::to_owned)
-            .collect();
+    fn parse_check_test_line_numbers_match(&self, line: &str) -> bool {
+        self.parse_name_directive(line, "check-test-line-numbers-match")
+    }
 
-        match strs.len() {
-            1 => (strs.pop().unwrap(), "".to_owned()),
-            2 => {
-                let end = strs.pop().unwrap();
-                (strs.pop().unwrap(), end)
+    fn parse_env(&self, line: &str, name: &str) -> Option<(String, String)> {
+        self.parse_name_value_directive(line, name).map(|nv| {
+            // nv is either FOO or FOO=BAR
+            let mut strs: Vec = nv.splitn(2, '=')
+                .map(str::to_owned)
+                .collect();
+
+            match strs.len() {
+                1 => (strs.pop().unwrap(), "".to_owned()),
+                2 => {
+                    let end = strs.pop().unwrap();
+                    (strs.pop().unwrap(), end)
+                }
+                n => panic!("Expected 1 or 2 strings, not {}", n),
             }
-            n => panic!("Expected 1 or 2 strings, not {}", n),
-        }
-    })
-}
+        })
+    }
 
-fn parse_pp_exact(line: &str, testfile: &Path) -> Option {
-    if let Some(s) = parse_name_value_directive(line, "pp-exact") {
-        Some(PathBuf::from(&s))
-    } else {
-        if parse_name_directive(line, "pp-exact") {
-            testfile.file_name().map(PathBuf::from)
+    fn parse_pp_exact(&self, line: &str, testfile: &Path) -> Option {
+        if let Some(s) = self.parse_name_value_directive(line, "pp-exact") {
+            Some(PathBuf::from(&s))
         } else {
-            None
+            if self.parse_name_directive(line, "pp-exact") {
+                testfile.file_name().map(PathBuf::from)
+            } else {
+                None
+            }
         }
     }
-}
 
-fn parse_name_directive(line: &str, directive: &str) -> bool {
-    // This 'no-' rule is a quick hack to allow pretty-expanded and no-pretty-expanded to coexist
-    line.contains(directive) && !line.contains(&("no-".to_owned() + directive))
-}
+    fn parse_name_directive(&self, line: &str, directive: &str) -> bool {
+        // This 'no-' rule is a quick hack to allow pretty-expanded and
+        // no-pretty-expanded to coexist
+        line.contains(directive) && !line.contains(&("no-".to_owned() + directive))
+    }
 
-pub fn parse_name_value_directive(line: &str, directive: &str) -> Option {
-    let keycolon = format!("{}:", directive);
-    if let Some(colon) = line.find(&keycolon) {
-        let value = line[(colon + keycolon.len())..line.len()].to_owned();
-        debug!("{}: {}", directive, value);
-        Some(value)
-    } else {
-        None
+    pub fn parse_name_value_directive(&self, line: &str, directive: &str) -> Option {
+        let keycolon = format!("{}:", directive);
+        if let Some(colon) = line.find(&keycolon) {
+            let value = line[(colon + keycolon.len())..line.len()].to_owned();
+            debug!("{}: {}", directive, value);
+            Some(expand_variables(value, self))
+        } else {
+            None
+        }
     }
 }
 
@@ -528,3 +540,24 @@ pub fn lldb_version_to_int(version_string: &str) -> isize {
     let major: isize = version_string.parse().ok().expect(&error_string);
     return major;
 }
+
+fn expand_variables(mut value: String, config: &Config) -> String {
+    const CWD: &'static str = "{{cwd}}";
+    const SRC_BASE: &'static str = "{{src-base}}";
+    const BUILD_BASE: &'static str = "{{build-base}}";
+
+    if value.contains(CWD) {
+        let cwd = env::current_dir().unwrap();
+        value = value.replace(CWD, &cwd.to_string_lossy());
+    }
+
+    if value.contains(SRC_BASE) {
+        value = value.replace(SRC_BASE, &config.src_base.to_string_lossy());
+    }
+
+    if value.contains(BUILD_BASE) {
+        value = value.replace(BUILD_BASE, &config.build_base.to_string_lossy());
+    }
+
+    value
+}
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 7fb296c19f6..1348c855249 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -16,7 +16,6 @@ use errors::{self, ErrorKind, Error};
 use filetime::FileTime;
 use json;
 use header::TestProps;
-use header;
 use procsrv;
 use test::TestPaths;
 use uidiff;
@@ -57,7 +56,7 @@ pub fn run(config: Config, testpaths: &TestPaths) {
         print!("\n\n");
     }
     debug!("running {:?}", testpaths.file.display());
-    let base_props = TestProps::from_file(&testpaths.file);
+    let base_props = TestProps::from_file(&testpaths.file, &config);
 
     let base_cx = TestCx { config: &config,
                            props: &base_props,
@@ -70,7 +69,7 @@ pub fn run(config: Config, testpaths: &TestPaths) {
     } else {
         for revision in &base_props.revisions {
             let mut revision_props = base_props.clone();
-            revision_props.load_from(&testpaths.file, Some(&revision));
+            revision_props.load_from(&testpaths.file, Some(&revision), &config);
             let rev_cx = TestCx {
                 config: &config,
                 props: &revision_props,
@@ -867,13 +866,13 @@ actual:\n\
                     }
 
                     for &(ref command_directive, ref check_directive) in &directives {
-                        header::parse_name_value_directive(
+                        self.config.parse_name_value_directive(
                             &line,
                             &command_directive).map(|cmd| {
                                 commands.push(cmd)
                             });
 
-                        header::parse_name_value_directive(
+                        self.config.parse_name_value_directive(
                             &line,
                             &check_directive).map(|cmd| {
                                 check_lines.push(cmd)
@@ -1158,7 +1157,9 @@ actual:\n\
         if self.props.build_aux_docs {
             for rel_ab in &self.props.aux_builds {
                 let aux_testpaths = self.compute_aux_test_paths(rel_ab);
-                let aux_props = self.props.from_aux_file(&aux_testpaths.file, self.revision);
+                let aux_props = self.props.from_aux_file(&aux_testpaths.file,
+                                                         self.revision,
+                                                         self.config);
                 let aux_cx = TestCx {
                     config: self.config,
                     props: &aux_props,
@@ -1279,7 +1280,9 @@ actual:\n\
 
         for rel_ab in &self.props.aux_builds {
             let aux_testpaths = self.compute_aux_test_paths(rel_ab);
-            let aux_props = self.props.from_aux_file(&aux_testpaths.file, self.revision);
+            let aux_props = self.props.from_aux_file(&aux_testpaths.file,
+                                                     self.revision,
+                                                     self.config);
             let mut crate_type = if aux_props.no_prefer_dynamic {
                 Vec::new()
             } else {
-- 
cgit 1.4.1-3-g733a5


From b48eb5e0be2a6e06d9629f770288c46f7bcb326c Mon Sep 17 00:00:00 2001
From: Gianni Ciccarelli 
Date: Wed, 26 Apr 2017 03:17:48 +0000
Subject:     support `default impl` for specialization

    `[default] [unsafe] impl` and typecheck
---
 src/grammar/parser-lalr.y                          | 29 +++++++++++-----------
 src/librustc/hir/lowering.rs                       |  2 +-
 src/librustc/traits/util.rs                        |  5 ++++
 src/librustc_typeck/check/mod.rs                   |  6 ++---
 src/libsyntax/feature_gate.rs                      | 11 +++-----
 src/libsyntax/parse/parser.rs                      | 15 +++++------
 .../defaultimpl/specialization-basics-unsafe.rs    | 22 ++++++++--------
 7 files changed, 44 insertions(+), 46 deletions(-)

(limited to 'src/libsyntax/parse')

diff --git a/src/grammar/parser-lalr.y b/src/grammar/parser-lalr.y
index 69ba0c9098b..c9fcdf7647b 100644
--- a/src/grammar/parser-lalr.y
+++ b/src/grammar/parser-lalr.y
@@ -535,10 +535,11 @@ maybe_unsafe
 | %empty { $$ = mk_none(); }
 ;
 
-maybe_default_impl
-:         IMPL { $$ = mk_none(); }
-| DEFAULT IMPL { $$ = $1 }
-;
+maybe_default_maybe_unsafe
+: DEFAULT UNSAFE { $$ = mk_atom("DefaultUnsafe"); }
+| DEFAULT        { $$ = mk_atom("Default"); }
+|         UNSAFE { $$ = mk_atom("Unsafe"); }
+| %empty { $$ = mk_none(); }
 
 trait_method
 : type_method { $$ = mk_node("Required", 1, $1); }
@@ -594,27 +595,27 @@ impl_method
 // they are ambiguous with traits. We do the same here, regrettably,
 // by splitting ty into ty and ty_prim.
 item_impl
-: maybe_unsafe maybe_default_impl generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
+: maybe_default_maybe_unsafe IMPL generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
 {
-  $$ = mk_node("ItemImpl", 6, $1, $3, $4, $5, $7, $8, $2);
+  $$ = mk_node("ItemImpl", 6, $1, $3, $4, $5, $7, $8);
 }
-| maybe_unsafe maybe_default_impl generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
+| maybe_default_maybe_unsafe IMPL generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
 {
-  $$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10, $2);
+  $$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10);
 }
-| maybe_unsafe maybe_default_impl generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
+| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
 {
-  $$ = mk_node("ItemImpl", 6, $3, $4, $6, $7, $9, $10, $2);
+  $$ = mk_node("ItemImpl", 6, $3, $4, $6, $7, $9, $10);
 }
-| maybe_unsafe maybe_default_impl generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
+| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}'
 {
-  $$ = mk_node("ItemImplNeg", 7, $1, $3, $5, $7, $8, $10, $11, $2);
+  $$ = mk_node("ItemImplNeg", 7, $1, $3, $5, $7, $8, $10, $11);
 }
-| maybe_unsafe maybe_default_impl generic_params trait_ref FOR DOTDOT '{' '}'
+| maybe_default_maybe_unsafe IMPL generic_params trait_ref FOR DOTDOT '{' '}'
 {
   $$ = mk_node("ItemImplDefault", 3, $1, $3, $4);
 }
-| maybe_unsafe maybe_default_impl generic_params '!' trait_ref FOR DOTDOT '{' '}'
+| maybe_default_maybe_unsafe IMPL generic_params '!' trait_ref FOR DOTDOT '{' '}'
 {
   $$ = mk_node("ItemImplDefaultNeg", 3, $1, $3, $4);
 }
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 8dda297e897..8f4dce5a783 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1363,7 +1363,7 @@ impl<'a> LoweringContext<'a> {
             ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"),
         }
 
-        // [1] `defaultness.has_value()` is necer called for an `impl`, always `true` in order to
+        // [1] `defaultness.has_value()` is never called for an `impl`, always `true` in order to
         //     not cause an assertion failure inside the `lower_defaultness` function
     }
 
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index 4aa7950de8f..e7c61dde768 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -14,6 +14,7 @@ use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef};
 use ty::outlives::Component;
 use util::nodemap::FxHashSet;
 use hir::{self};
+use traits::specialize::specialization_graph::NodeItem;
 
 use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext, Normalized};
 
@@ -525,6 +526,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             }
         }
     }
+
+    pub fn impl_item_is_final(self, node_item: &NodeItem) -> bool {
+        node_item.item.is_final() && !self.impl_is_default(node_item.node.def_id())
+    }
 }
 
 pub enum TupleArgumentsFlag { Yes, No }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a00d1ad0eae..631e09d831d 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1141,10 +1141,8 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         .map(|node_item| node_item.map(|parent| parent.defaultness));
 
     if let Some(parent) = parent {
-        if parent.item.is_final() {
-            if !tcx.impl_is_default(parent.node.def_id()) {
-                report_forbidden_specialization(tcx, impl_item, parent.node.def_id());
-            }
+        if tcx.impl_item_is_final(&parent) {
+            report_forbidden_specialization(tcx, impl_item, parent.node.def_id());
         }
     }
 
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 152a4e7ee1a..b6a2c983fd4 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -1226,13 +1226,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                     _ => {}
                 }
 
-                match defaultness {
-                    ast::Defaultness::Default => {
-                        gate_feature_post!(&self, specialization,
-                                      i.span,
-                                      "specialization is unstable");
-                    }
-                    _ => {}
+                if let ast::Defaultness::Default = defaultness {
+                    gate_feature_post!(&self, specialization,
+                                       i.span,
+                                       "specialization is unstable");
                 }
             }
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 2c10fff03db..f806e1e3bde 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -4918,12 +4918,9 @@ impl<'a> Parser<'a> {
                                           allowed to have generics");
             }
 
-            match defaultness {
-                ast::Defaultness::Default => {
-                    self.span_err(impl_span, "`default impl` is not allowed for \
-                                               default trait implementations");
-                }
-                _ => {}
+            if let ast::Defaultness::Default = defaultness {
+                self.span_err(impl_span, "`default impl` is not allowed for \
+                                         default trait implementations");
             }
 
             self.expect(&token::OpenDelim(token::Brace))?;
@@ -5768,13 +5765,13 @@ impl<'a> Parser<'a> {
         }
         if (self.check_keyword(keywords::Unsafe) &&
             self.look_ahead(1, |t| t.is_keyword(keywords::Impl))) ||
-           (self.check_keyword(keywords::Unsafe) &&
-            self.look_ahead(1, |t| t.is_keyword(keywords::Default)) &&
+           (self.check_keyword(keywords::Default) &&
+            self.look_ahead(1, |t| t.is_keyword(keywords::Unsafe)) &&
             self.look_ahead(2, |t| t.is_keyword(keywords::Impl)))
         {
             // IMPL ITEM
-            self.expect_keyword(keywords::Unsafe)?;
             let defaultness = self.parse_defaultness()?;
+            self.expect_keyword(keywords::Unsafe)?;
             self.expect_keyword(keywords::Impl)?;
             let (ident,
                  item_,
diff --git a/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs b/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs
index 9376d0db2df..7daecc842f3 100644
--- a/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs
+++ b/src/test/run-pass/specialization/defaultimpl/specialization-basics-unsafe.rs
@@ -17,61 +17,61 @@ unsafe trait Foo {
     fn foo(&self) -> &'static str;
 }
 
-unsafe default impl Foo for T {
+default unsafe impl Foo for T {
     fn foo(&self) -> &'static str {
         "generic"
     }
 }
 
-unsafe default impl Foo for T {
+default unsafe impl Foo for T {
     fn foo(&self) -> &'static str {
         "generic Clone"
     }
 }
 
-unsafe default impl Foo for (T, U) where T: Clone, U: Clone {
+default unsafe impl Foo for (T, U) where T: Clone, U: Clone {
     fn foo(&self) -> &'static str {
         "generic pair"
     }
 }
 
-unsafe default impl Foo for (T, T) {
+default unsafe impl Foo for (T, T) {
     fn foo(&self) -> &'static str {
         "generic uniform pair"
     }
 }
 
-unsafe default impl Foo for (u8, u32) {
+default unsafe impl Foo for (u8, u32) {
     fn foo(&self) -> &'static str {
         "(u8, u32)"
     }
 }
 
-unsafe default impl Foo for (u8, u8) {
+default unsafe impl Foo for (u8, u8) {
     fn foo(&self) -> &'static str {
         "(u8, u8)"
     }
 }
 
-unsafe default impl Foo for Vec {
+default unsafe impl Foo for Vec {
     fn foo(&self) -> &'static str {
         "generic Vec"
     }
 }
 
-unsafe impl Foo for Vec {
+default unsafe impl Foo for Vec {
     fn foo(&self) -> &'static str {
         "Vec"
     }
 }
 
-unsafe impl Foo for String {
+default unsafe impl Foo for String {
     fn foo(&self) -> &'static str {
         "String"
     }
 }
 
-unsafe impl Foo for i32 {
+default unsafe impl Foo for i32 {
     fn foo(&self) -> &'static str {
         "i32"
     }
@@ -80,7 +80,7 @@ unsafe impl Foo for i32 {
 struct NotClone;
 
 unsafe trait MyMarker {}
-unsafe default impl Foo for T {
+default unsafe impl Foo for T {
     fn foo(&self) -> &'static str {
         "generic Clone + MyMarker"
     }
-- 
cgit 1.4.1-3-g733a5


From 05329e578014ee1e9a0a45658e5fba60f6b06e83 Mon Sep 17 00:00:00 2001
From: Tommy Ip 
Date: Thu, 4 May 2017 13:14:39 +0100
Subject: Remove use of `Self: Sized` from libsyntax

The bound is not required for compiling but it prevents using `next_token()` from a trait object.

Fixes #33506.
---
 src/libsyntax/parse/lexer/mod.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/libsyntax/parse')

diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index c2e5763237d..7d2a1b3c4a4 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -73,7 +73,7 @@ fn mk_sp(lo: BytePos, hi: BytePos) -> Span {
 }
 
 impl<'a> StringReader<'a> {
-    fn next_token(&mut self) -> TokenAndSpan where Self: Sized {
+    fn next_token(&mut self) -> TokenAndSpan {
         let res = self.try_next_token();
         self.unwrap_or_abort(res)
     }
-- 
cgit 1.4.1-3-g733a5


From a9d3b3498e20a926d5b1662eb576d7db230ca110 Mon Sep 17 00:00:00 2001
From: F001 
Date: Tue, 2 May 2017 23:31:47 -0700
Subject: Suggest `!` for bitwise negation when encountering a `~`

---
 src/libsyntax/parse/parser.rs               | 13 +++++++++++++
 src/test/ui/did_you_mean/issue-41679.rs     | 13 +++++++++++++
 src/test/ui/did_you_mean/issue-41679.stderr | 10 ++++++++++
 3 files changed, 36 insertions(+)
 create mode 100644 src/test/ui/did_you_mean/issue-41679.rs
 create mode 100644 src/test/ui/did_you_mean/issue-41679.stderr

(limited to 'src/libsyntax/parse')

diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index d252963274e..f99f39dae6b 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2700,6 +2700,19 @@ impl<'a> Parser<'a> {
                 let (span, e) = self.interpolated_or_expr_span(e)?;
                 (span, self.mk_unary(UnOp::Not, e))
             }
+            // Suggest `!` for bitwise negation when encountering a `~`
+            token::Tilde => {
+                self.bump();
+                let e = self.parse_prefix_expr(None);
+                let (span, e) = self.interpolated_or_expr_span(e)?;
+                let span_of_tilde = lo;
+                let mut err = self.diagnostic().struct_span_err(span_of_tilde,
+                        "`~` can not be used as an unary operator");
+                err.span_label(span_of_tilde, &"did you mean `!`?");
+                err.help("use `!` instead of `~` if you meant to perform bitwise negation");
+                err.emit();
+                (span, self.mk_unary(UnOp::Not, e))
+            }
             token::BinOp(token::Minus) => {
                 self.bump();
                 let e = self.parse_prefix_expr(None);
diff --git a/src/test/ui/did_you_mean/issue-41679.rs b/src/test/ui/did_you_mean/issue-41679.rs
new file mode 100644
index 00000000000..5091b9efc34
--- /dev/null
+++ b/src/test/ui/did_you_mean/issue-41679.rs
@@ -0,0 +1,13 @@
+// Copyright 2017 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.
+
+fn main() {
+    let x = ~1;
+}
diff --git a/src/test/ui/did_you_mean/issue-41679.stderr b/src/test/ui/did_you_mean/issue-41679.stderr
new file mode 100644
index 00000000000..5a89ec96e24
--- /dev/null
+++ b/src/test/ui/did_you_mean/issue-41679.stderr
@@ -0,0 +1,10 @@
+error: `~` can not be used as an unary operator
+  --> $DIR/issue-41679.rs:12:13
+   |
+12 |     let x = ~1;
+   |             ^ did you mean `!`?
+   |
+   = help: use `!` instead of `~` if you meant to perform bitwise negation
+
+error: aborting due to previous error
+
-- 
cgit 1.4.1-3-g733a5


From a257d5afb037b45581657fe343d5df5a100f8d70 Mon Sep 17 00:00:00 2001
From: acdenisSK 
Date: Sat, 6 May 2017 16:06:38 +0200
Subject: Fix "an" usage

---
 .travis.yml                   | 2 +-
 src/libsyntax/parse/parser.rs | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

(limited to 'src/libsyntax/parse')

diff --git a/.travis.yml b/.travis.yml
index beb7b435cba..4fcf6f02def 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -194,7 +194,7 @@ after_failure:
 
 # Save tagged docker images we created and load them if they're available
 # Travis saves caches whether the build failed or not, nuke rustsrc if
-# the failure was while updating it (as it may be in an bad state)
+# the failure was while updating it (as it may be in a bad state)
 # https://github.com/travis-ci/travis-ci/issues/4472
 before_cache:
   - docker history -q rust-ci |
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index f99f39dae6b..268b3d08a80 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2707,7 +2707,7 @@ impl<'a> Parser<'a> {
                 let (span, e) = self.interpolated_or_expr_span(e)?;
                 let span_of_tilde = lo;
                 let mut err = self.diagnostic().struct_span_err(span_of_tilde,
-                        "`~` can not be used as an unary operator");
+                        "`~` can not be used as a unary operator");
                 err.span_label(span_of_tilde, &"did you mean `!`?");
                 err.help("use `!` instead of `~` if you meant to perform bitwise negation");
                 err.emit();
-- 
cgit 1.4.1-3-g733a5


From 0be875827fe64412f6c0eedc8f775f57137e7c55 Mon Sep 17 00:00:00 2001
From: ubsan 
Date: Wed, 3 May 2017 10:54:03 -0700
Subject: fix the easy features in libsyntax

---
 src/Cargo.lock                |  2 +-
 src/libsyntax/Cargo.toml      |  2 +-
 src/libsyntax/lib.rs          |  7 +------
 src/libsyntax/parse/mod.rs    |  8 ++++++--
 src/libsyntax/parse/parser.rs | 40 ++++++++++++++++++++--------------------
 src/libsyntax/print/pprust.rs |  2 +-
 6 files changed, 30 insertions(+), 31 deletions(-)

(limited to 'src/libsyntax/parse')

diff --git a/src/Cargo.lock b/src/Cargo.lock
index 21b167f6d42..3e0e6339692 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -858,8 +858,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 name = "syntax"
 version = "0.0.0"
 dependencies = [
+ "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc_bitflags 0.0.0",
  "rustc_data_structures 0.0.0",
  "rustc_errors 0.0.0",
  "serialize 0.0.0",
diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml
index 97d37266130..82e7cfa0032 100644
--- a/src/libsyntax/Cargo.toml
+++ b/src/libsyntax/Cargo.toml
@@ -11,7 +11,7 @@ crate-type = ["dylib"]
 [dependencies]
 serialize = { path = "../libserialize" }
 log = "0.3"
-rustc_bitflags = { path = "../librustc_bitflags" }
+bitflags = "0.8"
 syntax_pos = { path = "../libsyntax_pos" }
 rustc_errors = { path = "../librustc_errors" }
 rustc_data_structures = { path = "../librustc_data_structures" }
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 86ee1c5336d..89c67b88cbd 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -24,20 +24,15 @@
        test(attr(deny(warnings))))]
 #![deny(warnings)]
 
-#![feature(associated_consts)]
-#![feature(const_fn)]
-#![feature(optin_builtin_traits)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
-#![feature(str_escape)]
 #![feature(unicode)]
 #![feature(rustc_diagnostic_macros)]
-#![feature(specialization)]
 #![feature(i128_type)]
 
 extern crate serialize;
 #[macro_use] extern crate log;
-#[macro_use] #[no_link] extern crate rustc_bitflags;
+#[macro_use] extern crate bitflags;
 extern crate std_unicode;
 pub extern crate rustc_errors as errors;
 extern crate syntax_pos;
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 9d8f3b3d039..fe3ca1cf230 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -261,10 +261,14 @@ pub fn char_lit(lit: &str) -> (char, isize) {
     }
 }
 
+pub fn escape_default(s: &str) -> String {
+    s.chars().map(char::escape_default).flat_map(|x| x).collect()
+}
+
 /// Parse a string representing a string literal into its final form. Does
 /// unescaping.
 pub fn str_lit(lit: &str) -> String {
-    debug!("parse_str_lit: given {}", lit.escape_default());
+    debug!("parse_str_lit: given {}", escape_default(lit));
     let mut res = String::with_capacity(lit.len());
 
     // FIXME #8372: This could be a for-loop if it didn't borrow the iterator
@@ -339,7 +343,7 @@ pub fn str_lit(lit: &str) -> String {
 /// Parse a string representing a raw string literal into its final form. The
 /// only operation this does is convert embedded CRLF into a single LF.
 pub fn raw_str_lit(lit: &str) -> String {
-    debug!("raw_str_lit: given {}", lit.escape_default());
+    debug!("raw_str_lit: given {}", escape_default(lit));
     let mut res = String::with_capacity(lit.len());
 
     // FIXME #8372: This could be a for-loop if it didn't borrow the iterator
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index d252963274e..0a59d2a089d 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -64,7 +64,7 @@ use std::path::{self, Path, PathBuf};
 use std::slice;
 
 bitflags! {
-    flags Restrictions: u8 {
+    pub flags Restrictions: u8 {
         const RESTRICTION_STMT_EXPR         = 1 << 0,
         const RESTRICTION_NO_STRUCT_LITERAL = 1 << 1,
     }
@@ -2291,7 +2291,7 @@ impl<'a> Parser<'a> {
                     let e = if self.token.can_begin_expr()
                                && !(self.token == token::OpenDelim(token::Brace)
                                     && self.restrictions.contains(
-                                           Restrictions::RESTRICTION_NO_STRUCT_LITERAL)) {
+                                           RESTRICTION_NO_STRUCT_LITERAL)) {
                         Some(self.parse_expr()?)
                     } else {
                         None
@@ -2318,7 +2318,7 @@ impl<'a> Parser<'a> {
                         // This is a struct literal, unless we're prohibited
                         // from parsing struct literals here.
                         let prohibited = self.restrictions.contains(
-                            Restrictions::RESTRICTION_NO_STRUCT_LITERAL
+                            RESTRICTION_NO_STRUCT_LITERAL
                         );
                         if !prohibited {
                             return self.parse_struct_expr(lo, pth, attrs);
@@ -2722,7 +2722,7 @@ impl<'a> Parser<'a> {
             token::Ident(..) if self.token.is_keyword(keywords::In) => {
                 self.bump();
                 let place = self.parse_expr_res(
-                    Restrictions::RESTRICTION_NO_STRUCT_LITERAL,
+                    RESTRICTION_NO_STRUCT_LITERAL,
                     None,
                 )?;
                 let blk = self.parse_block()?;
@@ -2785,7 +2785,7 @@ impl<'a> Parser<'a> {
 
             let cur_op_span = self.span;
             let restrictions = if op.is_assign_like() {
-                self.restrictions & Restrictions::RESTRICTION_NO_STRUCT_LITERAL
+                self.restrictions & RESTRICTION_NO_STRUCT_LITERAL
             } else {
                 self.restrictions
             };
@@ -2835,13 +2835,13 @@ impl<'a> Parser<'a> {
 
             let rhs = match op.fixity() {
                 Fixity::Right => self.with_res(
-                    restrictions - Restrictions::RESTRICTION_STMT_EXPR,
+                    restrictions - RESTRICTION_STMT_EXPR,
                     |this| {
                         this.parse_assoc_expr_with(op.precedence(),
                             LhsExpr::NotYetParsed)
                 }),
                 Fixity::Left => self.with_res(
-                    restrictions - Restrictions::RESTRICTION_STMT_EXPR,
+                    restrictions - RESTRICTION_STMT_EXPR,
                     |this| {
                         this.parse_assoc_expr_with(op.precedence() + 1,
                             LhsExpr::NotYetParsed)
@@ -2849,7 +2849,7 @@ impl<'a> Parser<'a> {
                 // We currently have no non-associative operators that are not handled above by
                 // the special cases. The code is here only for future convenience.
                 Fixity::None => self.with_res(
-                    restrictions - Restrictions::RESTRICTION_STMT_EXPR,
+                    restrictions - RESTRICTION_STMT_EXPR,
                     |this| {
                         this.parse_assoc_expr_with(op.precedence() + 1,
                             LhsExpr::NotYetParsed)
@@ -2959,7 +2959,7 @@ impl<'a> Parser<'a> {
         if self.token.can_begin_expr() {
             // parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`.
             if self.token == token::OpenDelim(token::Brace) {
-                return !self.restrictions.contains(Restrictions::RESTRICTION_NO_STRUCT_LITERAL);
+                return !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL);
             }
             true
         } else {
@@ -2973,7 +2973,7 @@ impl<'a> Parser<'a> {
             return self.parse_if_let_expr(attrs);
         }
         let lo = self.prev_span;
-        let cond = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?;
+        let cond = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?;
         let thn = self.parse_block()?;
         let mut els: Option> = None;
         let mut hi = thn.span;
@@ -2992,7 +2992,7 @@ impl<'a> Parser<'a> {
         self.expect_keyword(keywords::Let)?;
         let pat = self.parse_pat()?;
         self.expect(&token::Eq)?;
-        let expr = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?;
+        let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?;
         let thn = self.parse_block()?;
         let (hi, els) = if self.eat_keyword(keywords::Else) {
             let expr = self.parse_else_expr()?;
@@ -3046,7 +3046,7 @@ impl<'a> Parser<'a> {
 
         let pat = self.parse_pat()?;
         self.expect_keyword(keywords::In)?;
-        let expr = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?;
+        let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?;
         let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
 
@@ -3061,7 +3061,7 @@ impl<'a> Parser<'a> {
         if self.token.is_keyword(keywords::Let) {
             return self.parse_while_let_expr(opt_ident, span_lo, attrs);
         }
-        let cond = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?;
+        let cond = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?;
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
         let span = span_lo.to(body.span);
@@ -3075,7 +3075,7 @@ impl<'a> Parser<'a> {
         self.expect_keyword(keywords::Let)?;
         let pat = self.parse_pat()?;
         self.expect(&token::Eq)?;
-        let expr = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?;
+        let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?;
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
         let span = span_lo.to(body.span);
@@ -3105,7 +3105,7 @@ impl<'a> Parser<'a> {
     fn parse_match_expr(&mut self, mut attrs: ThinVec) -> PResult<'a, P> {
         let match_span = self.prev_span;
         let lo = self.prev_span;
-        let discriminant = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL,
+        let discriminant = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL,
                                                None)?;
         if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) {
             if self.token == token::Token::Semi {
@@ -3146,7 +3146,7 @@ impl<'a> Parser<'a> {
             guard = Some(self.parse_expr()?);
         }
         self.expect(&token::FatArrow)?;
-        let expr = self.parse_expr_res(Restrictions::RESTRICTION_STMT_EXPR, None)?;
+        let expr = self.parse_expr_res(RESTRICTION_STMT_EXPR, None)?;
 
         let require_comma =
             !classify::expr_is_simple_block(&expr)
@@ -3727,7 +3727,7 @@ impl<'a> Parser<'a> {
         self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace)) &&
 
         // prevent `while catch {} {}`, `if catch {} {} else {}`, etc.
-        !self.restrictions.contains(Restrictions::RESTRICTION_NO_STRUCT_LITERAL)
+        !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL)
     }
 
     fn is_union_item(&self) -> bool {
@@ -3799,7 +3799,7 @@ impl<'a> Parser<'a> {
                     self.mk_expr(lo.to(hi), ExprKind::Path(None, pth), ThinVec::new())
                 };
 
-                let expr = self.with_res(Restrictions::RESTRICTION_STMT_EXPR, |this| {
+                let expr = self.with_res(RESTRICTION_STMT_EXPR, |this| {
                     let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?;
                     this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
                 })?;
@@ -3939,7 +3939,7 @@ impl<'a> Parser<'a> {
 
                     // Remainder are line-expr stmts.
                     let e = self.parse_expr_res(
-                        Restrictions::RESTRICTION_STMT_EXPR, Some(attrs.into()))?;
+                        RESTRICTION_STMT_EXPR, Some(attrs.into()))?;
                     Stmt {
                         id: ast::DUMMY_NODE_ID,
                         span: lo.to(e.span),
@@ -3952,7 +3952,7 @@ impl<'a> Parser<'a> {
 
     /// Is this expression a successfully-parsed statement?
     fn expr_is_complete(&mut self, e: &Expr) -> bool {
-        self.restrictions.contains(Restrictions::RESTRICTION_STMT_EXPR) &&
+        self.restrictions.contains(RESTRICTION_STMT_EXPR) &&
             !classify::expr_requires_semi_to_be_stmt(e)
     }
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index a911c21ed98..0c7e8fda837 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -677,7 +677,7 @@ pub trait PrintState<'a> {
                     style: ast::StrStyle) -> io::Result<()> {
         let st = match style {
             ast::StrStyle::Cooked => {
-                (format!("\"{}\"", st.escape_default()))
+                (format!("\"{}\"", parse::escape_default(st)))
             }
             ast::StrStyle::Raw(n) => {
                 (format!("r{delim}\"{string}\"{delim}",
-- 
cgit 1.4.1-3-g733a5


From dd87eabd83296baa4c2214d2cf3aeef24f753ba7 Mon Sep 17 00:00:00 2001
From: Oliver Schneider 
Date: Thu, 4 May 2017 14:17:23 +0200
Subject: Remove need for &format!(...) or &&"" dances in `span_label` calls

---
 src/librustc/hir/check_attr.rs                     |  4 +-
 src/librustc/infer/error_reporting/mod.rs          |  4 +-
 src/librustc/lint/context.rs                       |  4 +-
 src/librustc/middle/const_val.rs                   |  2 +-
 src/librustc/middle/effect.rs                      |  2 +-
 src/librustc/middle/entry.rs                       |  8 +--
 src/librustc/middle/intrinsicck.rs                 |  4 +-
 src/librustc/middle/resolve_lifetime.rs            | 14 ++---
 src/librustc/traits/error_reporting.rs             | 22 +++----
 src/librustc/ty/maps.rs                            |  2 +-
 src/librustc_borrowck/borrowck/check_loans.rs      | 50 ++++++++--------
 .../borrowck/gather_loans/move_error.rs            | 12 ++--
 src/librustc_borrowck/borrowck/mod.rs              | 60 +++++++++----------
 src/librustc_const_eval/check_match.rs             | 26 ++++----
 src/librustc_errors/diagnostic.rs                  |  5 +-
 src/librustc_errors/diagnostic_builder.rs          |  6 +-
 src/librustc_incremental/assert_dep_graph.rs       |  6 +-
 src/librustc_incremental/persist/dirty_clean.rs    |  2 +-
 src/librustc_lint/unused.rs                        |  2 +-
 src/librustc_metadata/creader.rs                   |  6 +-
 src/librustc_metadata/locator.rs                   |  2 +-
 src/librustc_mir/transform/qualify_consts.rs       | 16 ++---
 src/librustc_passes/ast_validation.rs              |  6 +-
 src/librustc_passes/consts.rs                      |  2 +-
 src/librustc_passes/loops.rs                       |  8 +--
 src/librustc_passes/static_recursion.rs            |  2 +-
 src/librustc_privacy/lib.rs                        |  6 +-
 src/librustc_resolve/lib.rs                        | 70 +++++++++++-----------
 src/librustc_resolve/macros.rs                     |  2 +-
 src/librustc_resolve/resolve_imports.rs            |  6 +-
 src/librustc_typeck/astconv.rs                     | 30 +++++-----
 src/librustc_typeck/check/_match.rs                | 22 +++----
 src/librustc_typeck/check/autoderef.rs             |  2 +-
 src/librustc_typeck/check/callee.rs                |  2 +-
 src/librustc_typeck/check/cast.rs                  |  4 +-
 src/librustc_typeck/check/coercion.rs              |  2 +-
 src/librustc_typeck/check/compare_method.rs        | 18 +++---
 src/librustc_typeck/check/intrinsic.rs             |  8 +--
 src/librustc_typeck/check/method/confirm.rs        |  4 +-
 src/librustc_typeck/check/method/suggest.rs        |  6 +-
 src/librustc_typeck/check/mod.rs                   | 66 ++++++++++----------
 src/librustc_typeck/check/op.rs                    |  6 +-
 src/librustc_typeck/check/wfcheck.rs               |  6 +-
 src/librustc_typeck/coherence/builtin.rs           | 10 ++--
 src/librustc_typeck/coherence/inherent_impls.rs    |  4 +-
 .../coherence/inherent_impls_overlap.rs            |  4 +-
 src/librustc_typeck/coherence/mod.rs               |  2 +-
 src/librustc_typeck/coherence/orphan.rs            |  4 +-
 src/librustc_typeck/coherence/overlap.rs           |  4 +-
 src/librustc_typeck/collect.rs                     |  8 +--
 src/librustc_typeck/impl_wf_check.rs               |  6 +-
 src/librustc_typeck/lib.rs                         |  6 +-
 src/librustdoc/html/format.rs                      |  4 +-
 src/libstd/fs.rs                                   |  2 +-
 src/libsyntax/attr.rs                              |  3 +-
 src/libsyntax/parse/parser.rs                      | 16 ++---
 56 files changed, 305 insertions(+), 305 deletions(-)

(limited to 'src/libsyntax/parse')

diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index bf292ccb8d8..f553c03d09b 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -43,7 +43,7 @@ impl<'a> CheckAttrVisitor<'a> {
     fn check_inline(&self, attr: &ast::Attribute, target: Target) {
         if target != Target::Fn {
             struct_span_err!(self.sess, attr.span, E0518, "attribute should be applied to function")
-                .span_label(attr.span, &format!("requires a function"))
+                .span_label(attr.span, "requires a function")
                 .emit();
         }
     }
@@ -123,7 +123,7 @@ impl<'a> CheckAttrVisitor<'a> {
                 _ => continue,
             };
             struct_span_err!(self.sess, attr.span, E0517, "{}", message)
-                .span_label(attr.span, &format!("requires {}", label))
+                .span_label(attr.span, format!("requires {}", label))
                 .emit();
         }
         if conflicting_reprs > 1 {
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 8f2bdd4e85c..4c27bade0f7 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -668,9 +668,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             }
         }
 
-        diag.span_label(span, &terr);
+        diag.span_label(span, terr.to_string());
         if let Some((sp, msg)) = secondary_span {
-            diag.span_label(sp, &msg);
+            diag.span_label(sp, msg);
         }
 
         self.note_error_origin(diag, &cause);
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 6947e7c3f40..6f3e84247f7 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -680,12 +680,12 @@ pub trait LintContext<'tcx>: Sized {
                                                             "{}({}) overruled by outer forbid({})",
                                                             level.as_str(), lint_name,
                                                             lint_name);
-                    diag_builder.span_label(span, &format!("overruled by previous forbid"));
+                    diag_builder.span_label(span, "overruled by previous forbid");
                     match now_source {
                         LintSource::Default => &mut diag_builder,
                         LintSource::Node(_, forbid_source_span) => {
                             diag_builder.span_label(forbid_source_span,
-                                                    &format!("`forbid` level set here"))
+                                                    "`forbid` level set here")
                         },
                         LintSource::CommandLine(_) => {
                             diag_builder.note("`forbid` lint level was set on command line")
diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index 74026abe64d..3bbaf5c9299 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -197,7 +197,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
     {
         match self.description() {
             ConstEvalErrDescription::Simple(message) => {
-                diag.span_label(self.span, &message);
+                diag.span_label(self.span, message);
             }
         }
 
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index d2b8ed8c297..e03948db368 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -74,7 +74,7 @@ impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> {
                     struct_span_err!(
                         self.tcx.sess, span, E0133,
                         "{} requires unsafe function or block", description)
-                        .span_label(span, &description)
+                        .span_label(span, description)
                         .emit();
                 }
             }
diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs
index 8da7560387f..24748b6cf65 100644
--- a/src/librustc/middle/entry.rs
+++ b/src/librustc/middle/entry.rs
@@ -128,8 +128,8 @@ fn find_item(item: &Item, ctxt: &mut EntryContext, at_root: bool) {
             } else {
                 struct_span_err!(ctxt.session, item.span, E0137,
                           "multiple functions with a #[main] attribute")
-                .span_label(item.span, &format!("additional #[main] function"))
-                .span_label(ctxt.attr_main_fn.unwrap().1, &format!("first #[main] function"))
+                .span_label(item.span, "additional #[main] function")
+                .span_label(ctxt.attr_main_fn.unwrap().1, "first #[main] function")
                 .emit();
             }
         },
@@ -141,8 +141,8 @@ fn find_item(item: &Item, ctxt: &mut EntryContext, at_root: bool) {
                     ctxt.session, item.span, E0138,
                     "multiple 'start' functions")
                     .span_label(ctxt.start_fn.unwrap().1,
-                                &format!("previous `start` function here"))
-                    .span_label(item.span, &format!("multiple `start` functions"))
+                                "previous `start` function here")
+                    .span_label(item.span, "multiple `start` functions")
                     .emit();
             }
         },
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index 435dd05358d..a759a9061f8 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -92,7 +92,7 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
                     struct_span_err!(self.infcx.tcx.sess, span, E0591,
                                      "`{}` is zero-sized and can't be transmuted to `{}`",
                                      from, to)
-                        .span_note(span, &format!("cast with `as` to a pointer instead"))
+                        .span_note(span, "cast with `as` to a pointer instead")
                         .emit();
                     return;
                 }
@@ -126,7 +126,7 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
                   from, skeleton_string(from, sk_from),
                   to, skeleton_string(to, sk_to))
             .span_label(span,
-                &format!("transmuting between {} and {}",
+                format!("transmuting between {} and {}",
                     skeleton_string(from, sk_from),
                     skeleton_string(to, sk_to)))
             .emit();
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index a8ba708cc2c..67b8dfb2d8e 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -574,9 +574,9 @@ fn signal_shadowing_problem(sess: &Session, name: ast::Name, orig: Original, sha
                                         {} name that is already in scope",
                                        shadower.kind.desc(), name, orig.kind.desc()))
     };
-    err.span_label(orig.span, &"first declared here");
+    err.span_label(orig.span, "first declared here");
     err.span_label(shadower.span,
-                   &format!("lifetime {} already in scope", name));
+                   format!("lifetime {} already in scope", name));
     err.emit();
 }
 
@@ -919,7 +919,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         } else {
             struct_span_err!(self.sess, lifetime_ref.span, E0261,
                 "use of undeclared lifetime name `{}`", lifetime_ref.name)
-                .span_label(lifetime_ref.span, &format!("undeclared lifetime"))
+                .span_label(lifetime_ref.span, "undeclared lifetime")
                 .emit();
         }
     }
@@ -1328,7 +1328,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
         } else {
             format!("expected lifetime parameter")
         };
-        err.span_label(span, &msg);
+        err.span_label(span, msg);
 
         if let Some(params) = error {
             if lifetime_refs.len() == 1 {
@@ -1438,7 +1438,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     let mut err = struct_span_err!(self.sess, lifetime.span, E0262,
                                   "invalid lifetime parameter name: `{}`", lifetime.name);
                     err.span_label(lifetime.span,
-                                   &format!("{} is a reserved lifetime name", lifetime.name));
+                                   format!("{} is a reserved lifetime name", lifetime.name));
                     err.emit();
                 }
             }
@@ -1452,9 +1452,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                                      "lifetime name `{}` declared twice in the same scope",
                                      lifetime_j.lifetime.name)
                         .span_label(lifetime_j.lifetime.span,
-                                    &format!("declared twice"))
+                                    "declared twice")
                         .span_label(lifetime_i.lifetime.span,
-                                   &format!("previous declaration here"))
+                                   "previous declaration here")
                         .emit();
                 }
             }
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index e846d74febf..152e3353994 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -484,12 +484,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
         if let Some(trait_item_span) = self.tcx.hir.span_if_local(trait_item_def_id) {
             let span = self.tcx.sess.codemap().def_span(trait_item_span);
-            err.span_label(span, &format!("definition of `{}` from trait", item_name));
+            err.span_label(span, format!("definition of `{}` from trait", item_name));
         }
 
         err.span_label(
             error_span,
-            &format!("impl has extra requirement {}", requirement));
+            format!("impl has extra requirement {}", requirement));
 
         if let Some(node_id) = lint_id {
             self.tcx.sess.add_lint_diagnostic(EXTRA_REQUIREMENT_IN_IMPL,
@@ -582,7 +582,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                         }
 
                         err.span_label(span,
-                                       &format!("{}the trait `{}` is not implemented for `{}`",
+                                       format!("{}the trait `{}` is not implemented for `{}`",
                                                 pre_message,
                                                 trait_ref,
                                                 trait_ref.self_ty()));
@@ -738,11 +738,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             expected_ref,
             found_ref);
 
-        err.span_label(span, &format!("{}", type_error));
+        err.span_label(span, format!("{}", type_error));
 
         if let Some(sp) = found_span {
-            err.span_label(span, &format!("requires `{}`", found_ref));
-            err.span_label(sp, &format!("implements `{}`", expected_ref));
+            err.span_label(span, format!("requires `{}`", found_ref));
+            err.span_label(sp, format!("implements `{}`", expected_ref));
         }
 
         err
@@ -765,12 +765,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             if expected == 1 { "" } else { "s" },
             if expected == 1 { "is" } else { "are" });
 
-        err.span_label(span, &format!("expected {} that takes {} argument{}",
+        err.span_label(span, format!("expected {} that takes {} argument{}",
                                       if is_closure { "closure" } else { "function" },
                                       expected,
                                       if expected == 1 { "" } else { "s" }));
         if let Some(span) = found_span {
-            err.span_label(span, &format!("takes {} argument{}",
+            err.span_label(span, format!("takes {} argument{}",
                                           found,
                                           if found == 1 { "" } else { "s" }));
         }
@@ -789,7 +789,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         let mut err = struct_span_err!(self.sess, span, E0072,
                                        "recursive type `{}` has infinite size",
                                        self.item_path_str(type_def_id));
-        err.span_label(span, &format!("recursive type has infinite size"));
+        err.span_label(span, "recursive type has infinite size");
         err.help(&format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \
                            at some point to make `{}` representable",
                           self.item_path_str(type_def_id)));
@@ -808,7 +808,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             self.sess, span, E0038,
             "the trait `{}` cannot be made into an object",
             trait_str);
-        err.span_label(span, &format!("the trait `{}` cannot be made into an object", trait_str));
+        err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str));
 
         let mut reported_violations = FxHashSet();
         for violation in violations {
@@ -1043,7 +1043,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                        "type annotations needed");
 
         for (target_span, label_message) in labels {
-            err.span_label(target_span, &label_message);
+            err.span_label(target_span, label_message);
         }
 
         err.emit();
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index a737e7caa3e..82a4c1e1e62 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -181,7 +181,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             let mut err =
                 struct_span_err!(self.sess, span, E0391,
                                  "unsupported cyclic reference between types/traits detected");
-            err.span_label(span, &format!("cyclic reference"));
+            err.span_label(span, "cyclic reference");
 
             err.span_note(stack[0].0, &format!("the cycle begins when {}...",
                                                stack[0].1.describe(self)));
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index 1c5a6c3985c..adabbe11f5e 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -469,13 +469,13 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                                                   nl, new_loan_msg);
                     err.span_label(
                             old_loan.span,
-                            &format!("first mutable borrow occurs here{}", old_loan_msg));
+                            format!("first mutable borrow occurs here{}", old_loan_msg));
                     err.span_label(
                             new_loan.span,
-                            &format!("second mutable borrow occurs here{}", new_loan_msg));
+                            format!("second mutable borrow occurs here{}", new_loan_msg));
                     err.span_label(
                             previous_end_span,
-                            &format!("first borrow ends here"));
+                            "first borrow ends here");
                     err
                 }
 
@@ -486,13 +486,13 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                                      nl);
                     err.span_label(
                             old_loan.span,
-                            &format!("first closure is constructed here"));
+                            "first closure is constructed here");
                     err.span_label(
                             new_loan.span,
-                            &format!("second closure is constructed here"));
+                            "second closure is constructed here");
                     err.span_label(
                             previous_end_span,
-                            &format!("borrow from first closure ends here"));
+                            "borrow from first closure ends here");
                     err
                 }
 
@@ -503,13 +503,13 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                                                    nl, ol_pronoun, old_loan_msg);
                     err.span_label(
                             new_loan.span,
-                            &format!("closure construction occurs here{}", new_loan_msg));
+                            format!("closure construction occurs here{}", new_loan_msg));
                     err.span_label(
                             old_loan.span,
-                            &format!("borrow occurs here{}", old_loan_msg));
+                            format!("borrow occurs here{}", old_loan_msg));
                     err.span_label(
                             previous_end_span,
-                            &format!("borrow ends here"));
+                            "borrow ends here");
                     err
                 }
 
@@ -520,13 +520,13 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                                                    nl, new_loan_msg, new_loan.kind.to_user_str());
                     err.span_label(
                             new_loan.span,
-                            &format!("borrow occurs here{}", new_loan_msg));
+                            format!("borrow occurs here{}", new_loan_msg));
                     err.span_label(
                             old_loan.span,
-                            &format!("closure construction occurs here{}", old_loan_msg));
+                            format!("closure construction occurs here{}", old_loan_msg));
                     err.span_label(
                             previous_end_span,
-                            &format!("borrow from closure ends here"));
+                            "borrow from closure ends here");
                     err
                 }
 
@@ -542,17 +542,17 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                                                    old_loan_msg);
                     err.span_label(
                             new_loan.span,
-                            &format!("{} borrow occurs here{}",
+                            format!("{} borrow occurs here{}",
                                      new_loan.kind.to_user_str(),
                                      new_loan_msg));
                     err.span_label(
                             old_loan.span,
-                            &format!("{} borrow occurs here{}",
+                            format!("{} borrow occurs here{}",
                                      old_loan.kind.to_user_str(),
                                      old_loan_msg));
                     err.span_label(
                             previous_end_span,
-                            &format!("{} borrow ends here",
+                            format!("{} borrow ends here",
                                      old_loan.kind.to_user_str()));
                     err
                 }
@@ -562,7 +562,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                 euv::ClosureCapture(span) => {
                     err.span_label(
                         span,
-                        &format!("borrow occurs due to use of `{}` in closure", nl));
+                        format!("borrow occurs due to use of `{}` in closure", nl));
                 }
                 _ => { }
             }
@@ -571,7 +571,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                 euv::ClosureCapture(span) => {
                     err.span_label(
                         span,
-                        &format!("previous borrow occurs due to use of `{}` in closure",
+                        format!("previous borrow occurs due to use of `{}` in closure",
                                  ol));
                 }
                 _ => { }
@@ -633,11 +633,11 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                                  "cannot use `{}` because it was mutably borrowed",
                                  &self.bccx.loan_path_to_string(copy_path))
                     .span_label(loan_span,
-                               &format!("borrow of `{}` occurs here",
+                               format!("borrow of `{}` occurs here",
                                        &self.bccx.loan_path_to_string(&loan_path))
                                )
                     .span_label(span,
-                               &format!("use of borrowed `{}`",
+                               format!("use of borrowed `{}`",
                                         &self.bccx.loan_path_to_string(&loan_path)))
                     .emit();
             }
@@ -662,12 +662,12 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                                          &self.bccx.loan_path_to_string(move_path));
                         err.span_label(
                             loan_span,
-                            &format!("borrow of `{}` occurs here",
+                            format!("borrow of `{}` occurs here",
                                     &self.bccx.loan_path_to_string(&loan_path))
                             );
                         err.span_label(
                             span,
-                            &format!("move into closure occurs here")
+                            "move into closure occurs here"
                             );
                         err
                     }
@@ -679,12 +679,12 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                                          &self.bccx.loan_path_to_string(move_path));
                         err.span_label(
                             loan_span,
-                            &format!("borrow of `{}` occurs here",
+                            format!("borrow of `{}` occurs here",
                                     &self.bccx.loan_path_to_string(&loan_path))
                             );
                         err.span_label(
                             span,
-                            &format!("move out of `{}` occurs here",
+                            format!("move out of `{}` occurs here",
                                 &self.bccx.loan_path_to_string(move_path))
                             );
                         err
@@ -857,10 +857,10 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                          "cannot assign to `{}` because it is borrowed",
                          self.bccx.loan_path_to_string(loan_path))
             .span_label(loan.span,
-                       &format!("borrow of `{}` occurs here",
+                       format!("borrow of `{}` occurs here",
                                self.bccx.loan_path_to_string(loan_path)))
             .span_label(span,
-                       &format!("assignment to borrowed `{}` occurs here",
+                       format!("assignment to borrowed `{}` occurs here",
                                self.bccx.loan_path_to_string(loan_path)))
             .emit();
     }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
index b7ce9d98233..1ee6d565d0d 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
@@ -94,7 +94,7 @@ fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &Vec(bccx: &BorrowckCtxt<'a, 'tcx>,
                              move_from.descriptive_string(bccx.tcx));
             err.span_label(
                 move_from.span,
-                &format!("cannot move out of {}", move_from.descriptive_string(bccx.tcx))
+                format!("cannot move out of {}", move_from.descriptive_string(bccx.tcx))
                 );
             err
         }
@@ -160,7 +160,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                                    "cannot move out of type `{}`, \
                                                     a non-copy array",
                                                    b.ty);
-                    err.span_label(move_from.span, &format!("cannot move out of here"));
+                    err.span_label(move_from.span, "cannot move out of here");
                     err
                 }
                 (_, Kind::Pattern) => {
@@ -177,7 +177,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                                    "cannot move out of type `{}`, \
                                                    which implements the `Drop` trait",
                                                    b.ty);
-                    err.span_label(move_from.span, &format!("cannot move out of here"));
+                    err.span_label(move_from.span, "cannot move out of here");
                     err
                 },
                 _ => {
@@ -198,12 +198,12 @@ fn note_move_destination(mut err: DiagnosticBuilder,
     if is_first_note {
         err.span_label(
             move_to_span,
-            &format!("hint: to prevent move, use `ref {0}` or `ref mut {0}`",
+            format!("hint: to prevent move, use `ref {0}` or `ref mut {0}`",
                      pat_name));
         err
     } else {
         err.span_label(move_to_span,
-                      &format!("...and here (use `ref {0}` or `ref mut {0}`)",
+                      format!("...and here (use `ref {0}` or `ref mut {0}`)",
                                pat_name));
         err
     }
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index f8073455bd0..7eb73a87532 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -546,7 +546,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                     "{} of possibly uninitialized variable: `{}`",
                     verb,
                     self.loan_path_to_string(lp))
-                .span_label(use_span, &format!("use of possibly uninitialized `{}`",
+                .span_label(use_span, format!("use of possibly uninitialized `{}`",
                     self.loan_path_to_string(lp)))
                 .emit();
                 return;
@@ -616,12 +616,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
         err = if use_span == move_span {
             err.span_label(
                 use_span,
-                &format!("value moved{} here in previous iteration of loop",
+                format!("value moved{} here in previous iteration of loop",
                          move_note));
             err
         } else {
-            err.span_label(use_span, &format!("value {} here after move", verb_participle))
-               .span_label(move_span, &format!("value moved{} here", move_note));
+            err.span_label(use_span, format!("value {} here after move", verb_participle))
+               .span_label(move_span, format!("value moved{} here", move_note));
             err
         };
 
@@ -657,9 +657,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
             self.tcx.sess, span, E0384,
             "re-assignment of immutable variable `{}`",
             self.loan_path_to_string(lp));
-        err.span_label(span, &format!("re-assignment of immutable variable"));
+        err.span_label(span, "re-assignment of immutable variable");
         if span != assign.span {
-            err.span_label(assign.span, &format!("first assignment to `{}`",
+            err.span_label(assign.span, format!("first assignment to `{}`",
                                               self.loan_path_to_string(lp)));
         }
         err.emit();
@@ -821,7 +821,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                 let mut err = struct_span_err!(
                     self.tcx.sess, span, E0389,
                     "{} in a `&` reference", prefix);
-                err.span_label(span, &"assignment into an immutable reference");
+                err.span_label(span, "assignment into an immutable reference");
                 err
             }
         };
@@ -914,7 +914,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                         }
                         db.span_label(
                             let_span,
-                            &format!("consider changing this to `mut {}`", snippet)
+                            format!("consider changing this to `mut {}`", snippet)
                         );
                     }
                 }
@@ -927,7 +927,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                         if let Ok(snippet) = snippet {
                             db.span_label(
                                 let_span,
-                                &format!("consider changing this to `{}`",
+                                format!("consider changing this to `{}`",
                                          snippet.replace("ref ", "ref mut "))
                             );
                         }
@@ -936,7 +936,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                         if let (Some(local_ty), is_implicit_self) = self.local_ty(node_id) {
                             if let Some(msg) =
                                  self.suggest_mut_for_immutable(local_ty, is_implicit_self) {
-                                db.span_label(local_ty.span, &msg);
+                                db.span_label(local_ty.span, msg);
                             }
                         }
                     }
@@ -950,7 +950,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
 
                 if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(node_id) {
                     if let Some(msg) = self.suggest_mut_for_immutable(&field.ty, false) {
-                        db.span_label(field.ty.span, &msg);
+                        db.span_label(field.ty.span, msg);
                     }
                 }
             }
@@ -975,10 +975,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                           which is owned by the current function",
                          cmt_path_or_string)
             .span_label(capture_span,
-                       &format!("{} is borrowed here",
+                       format!("{} is borrowed here",
                                 cmt_path_or_string))
             .span_label(err.span,
-                       &format!("may outlive borrowed value {}",
+                       format!("may outlive borrowed value {}",
                                 cmt_path_or_string))
             .span_suggestion(err.span,
                              &format!("to force the closure to take ownership of {} \
@@ -1029,15 +1029,15 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                         match db.span.primary_span() {
                             Some(primary) => {
                                 db.span = MultiSpan::from_span(s);
-                                db.span_label(primary, &format!("capture occurs here"));
-                                db.span_label(s, &"does not live long enough");
+                                db.span_label(primary, "capture occurs here");
+                                db.span_label(s, "does not live long enough");
                                 true
                             }
                             None => false
                         }
                     }
                     _ => {
-                        db.span_label(error_span, &"does not live long enough");
+                        db.span_label(error_span, "does not live long enough");
                         false
                     }
                 };
@@ -1049,7 +1049,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                     (Some(s1), Some(s2)) if s1 == s2 => {
                         if !is_closure {
                             db.span = MultiSpan::from_span(s1);
-                            db.span_label(error_span, &value_msg);
+                            db.span_label(error_span, value_msg);
                             let msg = match opt_loan_path(&err.cmt) {
                                 None => value_kind.to_string(),
                                 Some(lp) => {
@@ -1057,29 +1057,29 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                                 }
                             };
                             db.span_label(s1,
-                                          &format!("{} dropped here while still borrowed", msg));
+                                          format!("{} dropped here while still borrowed", msg));
                         } else {
-                            db.span_label(s1, &format!("{} dropped before borrower", value_kind));
+                            db.span_label(s1, format!("{} dropped before borrower", value_kind));
                         }
                         db.note("values in a scope are dropped in the opposite order \
                                 they are created");
                     }
                     (Some(s1), Some(s2)) if !is_closure => {
                         db.span = MultiSpan::from_span(s2);
-                        db.span_label(error_span, &value_msg);
+                        db.span_label(error_span, value_msg);
                         let msg = match opt_loan_path(&err.cmt) {
                             None => value_kind.to_string(),
                             Some(lp) => {
                                 format!("`{}`", self.loan_path_to_string(&lp))
                             }
                         };
-                        db.span_label(s2, &format!("{} dropped here while still borrowed", msg));
-                        db.span_label(s1, &format!("{} needs to live until here", value_kind));
+                        db.span_label(s2, format!("{} dropped here while still borrowed", msg));
+                        db.span_label(s1, format!("{} needs to live until here", value_kind));
                     }
                     _ => {
                         match sub_span {
                             Some(s) => {
-                                db.span_label(s, &format!("{} needs to live until here",
+                                db.span_label(s, format!("{} needs to live until here",
                                                           value_kind));
                             }
                             None => {
@@ -1092,7 +1092,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                         }
                         match super_span {
                             Some(s) => {
-                                db.span_label(s, &format!("{} only lives until here", value_kind));
+                                db.span_label(s, format!("{} only lives until here", value_kind));
                             }
                             None => {
                                 self.tcx.note_and_explain_region(
@@ -1162,23 +1162,23 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \
             }
             _ => {
                 if let Categorization::Deref(..) = err.cmt.cat {
-                    db.span_label(*error_span, &"cannot borrow as mutable");
+                    db.span_label(*error_span, "cannot borrow as mutable");
                 } else if let Categorization::Local(local_id) = err.cmt.cat {
                     let span = self.tcx.hir.span(local_id);
                     if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) {
                         if snippet.starts_with("ref mut ") || snippet.starts_with("&mut ") {
-                            db.span_label(*error_span, &format!("cannot reborrow mutably"));
-                            db.span_label(*error_span, &format!("try removing `&mut` here"));
+                            db.span_label(*error_span, "cannot reborrow mutably");
+                            db.span_label(*error_span, "try removing `&mut` here");
                         } else {
-                            db.span_label(*error_span, &format!("cannot borrow mutably"));
+                            db.span_label(*error_span, "cannot borrow mutably");
                         }
                     } else {
-                        db.span_label(*error_span, &format!("cannot borrow mutably"));
+                        db.span_label(*error_span, "cannot borrow mutably");
                     }
                 } else if let Categorization::Interior(ref cmt, _) = err.cmt.cat {
                     if let mc::MutabilityCategory::McImmutable = cmt.mutbl {
                         db.span_label(*error_span,
-                                      &"cannot mutably borrow immutable field");
+                                      "cannot mutably borrow immutable field");
                     }
                 }
             }
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 6ec5f38aa5b..cd31290eb55 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -258,7 +258,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
                 "refutable pattern in {}: `{}` not covered",
                 origin, pattern_string
             );
-            diag.span_label(pat.span, &format!("pattern `{}` not covered", pattern_string));
+            diag.span_label(pat.span, format!("pattern `{}` not covered", pattern_string));
             diag.emit();
         });
     }
@@ -328,7 +328,7 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                                 let span = first_pat.0.span;
                                 struct_span_err!(cx.tcx.sess, span, E0162,
                                                 "irrefutable if-let pattern")
-                                    .span_label(span, &format!("irrefutable pattern"))
+                                    .span_label(span, "irrefutable pattern")
                                     .emit();
                                 printed_if_let_err = true;
                             }
@@ -355,7 +355,7 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                                 1 => {
                                     struct_span_err!(cx.tcx.sess, span, E0165,
                                                      "irrefutable while-let pattern")
-                                        .span_label(span, &format!("irrefutable pattern"))
+                                        .span_label(span, "irrefutable pattern")
                                         .emit();
                                 },
                                 _ => bug!(),
@@ -369,7 +369,7 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                             diagnostic.set_span(pat.span);
                             // if we had a catchall pattern, hint at that
                             if let Some(catchall) = catchall {
-                                diagnostic.span_label(pat.span, &"this is an unreachable pattern");
+                                diagnostic.span_label(pat.span, "this is an unreachable pattern");
                                 diagnostic.span_note(catchall, "this pattern matches any value");
                             }
                             cx.tcx.sess.add_lint_diagnostic(lint::builtin::UNREACHABLE_PATTERNS,
@@ -426,7 +426,7 @@ fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                         "refutable pattern in `for` loop binding: \
                                 `{}` not covered",
                                 pattern_string)
-                        .span_label(sp, &format!("pattern `{}` not covered", pattern_string))
+                        .span_label(sp, format!("pattern `{}` not covered", pattern_string))
                         .emit();
                 },
                 _ => {
@@ -453,7 +453,7 @@ fn check_exhaustive<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
                     create_e0004(cx.tcx.sess, sp,
                                  format!("non-exhaustive patterns: {} not covered",
                                          joined_patterns))
-                        .span_label(sp, &label_text)
+                        .span_label(sp, label_text)
                         .emit();
                 },
             }
@@ -485,18 +485,18 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
         if sub.map_or(false, |p| p.contains_bindings()) {
             struct_span_err!(cx.tcx.sess, p.span, E0007,
                              "cannot bind by-move with sub-bindings")
-                .span_label(p.span, &format!("binds an already bound by-move value by moving it"))
+                .span_label(p.span, "binds an already bound by-move value by moving it")
                 .emit();
         } else if has_guard {
             struct_span_err!(cx.tcx.sess, p.span, E0008,
                       "cannot bind by-move into a pattern guard")
-                .span_label(p.span, &format!("moves value into pattern guard"))
+                .span_label(p.span, "moves value into pattern guard")
                 .emit();
         } else if by_ref_span.is_some() {
             struct_span_err!(cx.tcx.sess, p.span, E0009,
                             "cannot bind by-move and by-ref in the same pattern")
-                    .span_label(p.span, &format!("by-move pattern here"))
-                    .span_label(by_ref_span.unwrap(), &format!("both by-ref and by-move used"))
+                    .span_label(p.span, "by-move pattern here")
+                    .span_label(by_ref_span.unwrap(), "both by-ref and by-move used")
                     .emit();
         }
     };
@@ -546,7 +546,7 @@ impl<'a, 'gcx, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'gcx> {
             ty::MutBorrow => {
                 struct_span_err!(self.cx.tcx.sess, span, E0301,
                           "cannot mutably borrow in a pattern guard")
-                    .span_label(span, &format!("borrowed mutably in pattern guard"))
+                    .span_label(span, "borrowed mutably in pattern guard")
                     .emit();
             }
             ty::ImmBorrow | ty::UniqueImmBorrow => {}
@@ -557,7 +557,7 @@ impl<'a, 'gcx, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'gcx> {
         match mode {
             MutateMode::JustWrite | MutateMode::WriteAndRead => {
                 struct_span_err!(self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard")
-                    .span_label(span, &format!("assignment in pattern guard"))
+                    .span_label(span, "assignment in pattern guard")
                     .emit();
             }
             MutateMode::Init => {}
@@ -588,7 +588,7 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for AtBindingPatternVisitor<'a, 'b, 'tcx> {
                 if !self.bindings_allowed {
                     struct_span_err!(self.cx.tcx.sess, pat.span, E0303,
                                      "pattern bindings are not allowed after an `@`")
-                        .span_label(pat.span,  &format!("not allowed after `@`"))
+                        .span_label(pat.span,  "not allowed after `@`")
                         .emit();
                 }
 
diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs
index 38fa35ecb12..0822f713499 100644
--- a/src/librustc_errors/diagnostic.rs
+++ b/src/librustc_errors/diagnostic.rs
@@ -114,9 +114,8 @@ impl Diagnostic {
     /// all, and you just supplied a `Span` to create the diagnostic,
     /// then the snippet will just include that `Span`, which is
     /// called the primary span.
-    pub fn span_label(&mut self, span: Span, label: &fmt::Display)
-                      -> &mut Self {
-        self.span.push_span_label(span, format!("{}", label));
+    pub fn span_label>(&mut self, span: Span, label: T) -> &mut Self {
+        self.span.push_span_label(span, label.into());
         self
     }
 
diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs
index 9dfd47b8464..a9c2bbeba2a 100644
--- a/src/librustc_errors/diagnostic_builder.rs
+++ b/src/librustc_errors/diagnostic_builder.rs
@@ -112,8 +112,10 @@ impl<'a> DiagnosticBuilder<'a> {
     /// all, and you just supplied a `Span` to create the diagnostic,
     /// then the snippet will just include that `Span`, which is
     /// called the primary span.
-    forward!(pub fn span_label(&mut self, span: Span, label: &fmt::Display)
-                               -> &mut Self);
+    pub fn span_label>(&mut self, span: Span, label: T) -> &mut Self {
+        self.diagnostic.span_label(span, label);
+        self
+    }
 
     forward!(pub fn note_expected_found(&mut self,
                                         label: &fmt::Display,
diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs
index 7905128bb6e..39fe2188f68 100644
--- a/src/librustc_incremental/assert_dep_graph.rs
+++ b/src/librustc_incremental/assert_dep_graph.rs
@@ -154,7 +154,7 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> {
                     None => {
                         self.tcx.sess.span_fatal(
                             attr.span,
-                            &format!("missing DepNode variant"));
+                            "missing DepNode variant");
                     }
                 };
                 self.then_this_would_need.push((attr.span,
@@ -201,7 +201,7 @@ fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         for &(target_span, _, _, _) in then_this_would_need {
             tcx.sess.span_err(
                 target_span,
-                &format!("no #[rustc_if_this_changed] annotation detected"));
+                "no #[rustc_if_this_changed] annotation detected");
 
         }
         return;
@@ -219,7 +219,7 @@ fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             } else {
                 tcx.sess.span_err(
                     target_span,
-                    &format!("OK"));
+                    "OK");
             }
         }
     }
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index b73b3e161f9..5facfe36efd 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -383,7 +383,7 @@ fn check_config(tcx: TyCtxt, attr: &Attribute) -> bool {
 
     tcx.sess.span_fatal(
         attr.span,
-        &format!("no cfg attribute"));
+        "no cfg attribute");
 }
 
 fn expect_associated_value(tcx: TyCtxt, item: &NestedMetaItem) -> ast::Name {
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 86bf209ccf8..93ff609a280 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -215,7 +215,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedUnsafe {
                 let mut db = cx.struct_span_lint(UNUSED_UNSAFE, blk.span,
                                                  "unnecessary `unsafe` block");
 
-                db.span_label(blk.span, &"unnecessary `unsafe` block");
+                db.span_label(blk.span, "unnecessary `unsafe` block");
                 if let Some((kind, id)) = is_enclosed(cx, blk.id) {
                     db.span_note(cx.tcx.hir.span(id),
                                  &format!("because it's nested under this `unsafe` {}", kind));
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 966e814e337..325511c9787 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -88,7 +88,7 @@ fn register_native_lib(sess: &Session,
             Some(span) => {
                 struct_span_err!(sess, span, E0454,
                                  "#[link(name = \"\")] given with empty name")
-                    .span_label(span, &format!("empty name given"))
+                    .span_label(span, "empty name given")
                     .emit();
             }
             None => {
@@ -1029,7 +1029,7 @@ impl<'a> CrateLoader<'a> {
                 Some(k) => {
                     struct_span_err!(self.sess, m.span, E0458,
                               "unknown kind: `{}`", k)
-                        .span_label(m.span, &format!("unknown kind")).emit();
+                        .span_label(m.span, "unknown kind").emit();
                     cstore::NativeUnknown
                 }
                 None => cstore::NativeUnknown
@@ -1042,7 +1042,7 @@ impl<'a> CrateLoader<'a> {
                 None => {
                     struct_span_err!(self.sess, m.span, E0459,
                                      "#[link(...)] specified without `name = \"foo\"`")
-                        .span_label(m.span, &format!("missing `name` argument")).emit();
+                        .span_label(m.span, "missing `name` argument").emit();
                     Symbol::intern("foo")
                 }
             };
diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs
index e8bc8b01652..84bb82de370 100644
--- a/src/librustc_metadata/locator.rs
+++ b/src/librustc_metadata/locator.rs
@@ -367,7 +367,7 @@ impl<'a> Context<'a> {
                 && self.triple != config::host_triple() {
                 err.note(&format!("the `{}` target may not be installed", self.triple));
             }
-            err.span_label(self.span, &format!("can't find crate"));
+            err.span_label(self.span, "can't find crate");
             err
         };
 
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 4b1c82f383f..0d592b4d72b 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -242,9 +242,9 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
                    to the crate attributes to enable");
         } else {
             self.find_drop_implementation_method_span()
-                .map(|span| err.span_label(span, &format!("destructor defined here")));
+                .map(|span| err.span_label(span, "destructor defined here"));
 
-            err.span_label(self.span, &format!("constants cannot have destructors"));
+            err.span_label(self.span, "constants cannot have destructors");
         }
 
         err.emit();
@@ -291,8 +291,8 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
                 "cannot refer to statics by value, use a constant instead"
             };
             struct_span_err!(self.tcx.sess, self.span, E0394, "{}", msg)
-                .span_label(self.span, &format!("referring to another static by value"))
-                .note(&format!("use the address-of operator or a constant instead"))
+                .span_label(self.span, "referring to another static by value")
+                .note("use the address-of operator or a constant instead")
                 .emit();
 
             // Replace STATIC with NOT_CONST to avoid further errors.
@@ -529,7 +529,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                                         "raw pointers cannot be dereferenced in {}s",
                                         this.mode)
                                     .span_label(this.span,
-                                        &format!("dereference of raw pointer in constant"))
+                                        "dereference of raw pointer in constant")
                                     .emit();
                                 }
                             }
@@ -645,7 +645,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                             struct_span_err!(self.tcx.sess,  self.span, E0017,
                                              "references in {}s may only refer \
                                               to immutable values", self.mode)
-                                .span_label(self.span, &format!("{}s require immutable values",
+                                .span_label(self.span, format!("{}s require immutable values",
                                                                 self.mode))
                                 .emit();
                         }
@@ -713,7 +713,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                             self.mode)
                         .span_label(
                             self.span,
-                            &format!("comparing raw pointers in static"))
+                            "comparing raw pointers in static")
                         .emit();
                     }
                 }
@@ -724,7 +724,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
                 if self.mode != Mode::Fn {
                     struct_span_err!(self.tcx.sess, self.span, E0010,
                                      "allocations are not allowed in {}s", self.mode)
-                        .span_label(self.span, &format!("allocation not allowed in {}s", self.mode))
+                        .span_label(self.span, format!("allocation not allowed in {}s", self.mode))
                         .emit();
                 }
             }
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 8c45a666945..d7fee7f3110 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -55,7 +55,7 @@ impl<'a> AstValidator<'a> {
                                            E0449,
                                            "unnecessary visibility qualifier");
             if vis == &Visibility::Public {
-                err.span_label(span, &format!("`pub` not needed here"));
+                err.span_label(span, "`pub` not needed here");
             }
             if let Some(note) = note {
                 err.note(note);
@@ -80,7 +80,7 @@ impl<'a> AstValidator<'a> {
             Constness::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"))
+                    .span_label(constness.span, "trait fns cannot be const")
                     .emit();
             }
             _ => {}
@@ -272,7 +272,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                                                    E0130,
                                                    "patterns aren't allowed in foreign function \
                                                     declarations");
-                    err.span_label(span, &format!("pattern not allowed in foreign function"));
+                    err.span_label(span, "pattern not allowed in foreign function");
                     if is_recent {
                         err.span_note(span,
                                       "this is a recent error, see issue #35203 for more details");
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 608238dfe37..a0998b1bd1b 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -180,7 +180,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
                     Ok(Ordering::Greater) => {
                         struct_span_err!(self.tcx.sess, start.span, E0030,
                             "lower range bound must be less than or equal to upper")
-                            .span_label(start.span, &format!("lower bound larger than upper bound"))
+                            .span_label(start.span, "lower bound larger than upper bound")
                             .emit();
                     }
                     Err(ErrorReported) => {}
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index 2ea235af103..21a4c007fb1 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -118,7 +118,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                                              "`break` with value from a `{}` loop",
                                              kind.name())
                                 .span_label(e.span,
-                                            &format!("can only break with a value inside `loop`"))
+                                            "can only break with a value inside `loop`")
                                 .emit();
                         }
                     }
@@ -154,12 +154,12 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
             Loop(_) => {}
             Closure => {
                 struct_span_err!(self.sess, span, E0267, "`{}` inside of a closure", name)
-                .span_label(span, &format!("cannot break inside of a closure"))
+                .span_label(span, "cannot break inside of a closure")
                 .emit();
             }
             Normal => {
                 struct_span_err!(self.sess, span, E0268, "`{}` outside of loop", name)
-                .span_label(span, &format!("cannot break outside of a loop"))
+                .span_label(span, "cannot break outside of a loop")
                 .emit();
             }
         }
@@ -169,7 +169,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
         struct_span_err!(self.sess, span, E0590,
                          "`break` or `continue` with no label in the condition of a `while` loop")
             .span_label(span,
-                        &format!("unlabeled `{}` in the condition of a `while` loop", cf_type))
+                        format!("unlabeled `{}` in the condition of a `while` loop", cf_type))
             .emit();
     }
 }
diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs
index d0bf49b7b33..8d455adc23c 100644
--- a/src/librustc_passes/static_recursion.rs
+++ b/src/librustc_passes/static_recursion.rs
@@ -138,7 +138,7 @@ impl<'a, 'b: 'a, 'hir: 'b> CheckItemRecursionVisitor<'a, 'b, 'hir> {
             });
             if !any_static {
                 struct_span_err!(self.sess, span, E0265, "recursive constant")
-                    .span_label(span, &format!("recursion not allowed in constant"))
+                    .span_label(span, "recursion not allowed in constant")
                     .emit();
             }
             return;
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 82c91727293..f63102433c1 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -433,7 +433,7 @@ impl<'a, 'tcx> NamePrivacyVisitor<'a, 'tcx> {
         if !def.is_enum() && !field.vis.is_accessible_from(self.current_item, self.tcx) {
             struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private",
                              field.name, def.variant_descr(), self.tcx.item_path_str(def.did))
-                .span_label(span, &format!("field `{}` is private", field.name))
+                .span_label(span, format!("field `{}` is private", field.name))
                 .emit();
         }
     }
@@ -926,7 +926,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
                     if self.has_pub_restricted || self.has_old_errors {
                         let mut err = struct_span_err!(self.tcx.sess, self.span, E0446,
                             "private type `{}` in public interface", ty);
-                        err.span_label(self.span, &format!("can't leak private type"));
+                        err.span_label(self.span, "can't leak private type");
                         err.emit();
                     } else {
                         self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
@@ -961,7 +961,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
                 if self.has_pub_restricted || self.has_old_errors {
                     struct_span_err!(self.tcx.sess, self.span, E0445,
                                      "private trait `{}` in public interface", trait_ref)
-                        .span_label(self.span, &format!(
+                        .span_label(self.span, format!(
                                     "private trait can't be public"))
                         .emit();
                 } else {
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index a4e9a8be49f..ac556270886 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -183,7 +183,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
                                            E0401,
                                            "can't use type parameters from outer function; \
                                            try using a local type parameter instead");
-            err.span_label(span, &format!("use of type variable from outer function"));
+            err.span_label(span, "use of type variable from outer function");
             err
         }
         ResolutionError::OuterTypeParameterContext => {
@@ -199,8 +199,8 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
                                             "the name `{}` is already used for a type parameter \
                                             in this type parameter list",
                                             name);
-             err.span_label(span, &format!("already used"));
-             err.span_label(first_use_span.clone(), &format!("first use of `{}`", name));
+             err.span_label(span, "already used");
+             err.span_label(first_use_span.clone(), format!("first use of `{}`", name));
              err
         }
         ResolutionError::MethodNotMemberOfTrait(method, trait_) => {
@@ -210,7 +210,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
                                            "method `{}` is not a member of trait `{}`",
                                            method,
                                            trait_);
-            err.span_label(span, &format!("not a member of trait `{}`", trait_));
+            err.span_label(span, format!("not a member of trait `{}`", trait_));
             err
         }
         ResolutionError::TypeNotMemberOfTrait(type_, trait_) => {
@@ -220,7 +220,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
                              "type `{}` is not a member of trait `{}`",
                              type_,
                              trait_);
-            err.span_label(span, &format!("not a member of trait `{}`", trait_));
+            err.span_label(span, format!("not a member of trait `{}`", trait_));
             err
         }
         ResolutionError::ConstNotMemberOfTrait(const_, trait_) => {
@@ -230,7 +230,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
                              "const `{}` is not a member of trait `{}`",
                              const_,
                              trait_);
-            err.span_label(span, &format!("not a member of trait `{}`", trait_));
+            err.span_label(span, format!("not a member of trait `{}`", trait_));
             err
         }
         ResolutionError::VariableNotBoundInPattern(binding_error) => {
@@ -239,11 +239,11 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
             let msg = format!("variable `{}` is not bound in all patterns", binding_error.name);
             let mut err = resolver.session.struct_span_err_with_code(msp, &msg, "E0408");
             for sp in target_sp {
-                err.span_label(sp, &format!("pattern doesn't bind `{}`", binding_error.name));
+                err.span_label(sp, format!("pattern doesn't bind `{}`", binding_error.name));
             }
             let origin_sp = binding_error.origin.iter().map(|x| *x).collect::>();
             for sp in origin_sp {
-                err.span_label(sp, &"variable not in all patterns");
+                err.span_label(sp, "variable not in all patterns");
             }
             err
         }
@@ -255,8 +255,8 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
                              "variable `{}` is bound in inconsistent \
                              ways within the same match arm",
                              variable_name);
-            err.span_label(span, &format!("bound in different ways"));
-            err.span_label(first_binding_span, &format!("first binding"));
+            err.span_label(span, "bound in different ways");
+            err.span_label(first_binding_span, "first binding");
             err
         }
         ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => {
@@ -265,7 +265,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
                              E0415,
                              "identifier `{}` is bound more than once in this parameter list",
                              identifier);
-            err.span_label(span, &format!("used as parameter more than once"));
+            err.span_label(span, "used as parameter more than once");
             err
         }
         ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => {
@@ -274,7 +274,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
                              E0416,
                              "identifier `{}` is bound more than once in the same pattern",
                              identifier);
-            err.span_label(span, &format!("used in a pattern more than once"));
+            err.span_label(span, "used in a pattern more than once");
             err
         }
         ResolutionError::UndeclaredLabel(name) => {
@@ -283,7 +283,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
                                            E0426,
                                            "use of undeclared label `{}`",
                                            name);
-            err.span_label(span, &format!("undeclared label `{}`",&name));
+            err.span_label(span, format!("undeclared label `{}`", name));
             err
         }
         ResolutionError::SelfImportsOnlyAllowedWithin => {
@@ -313,14 +313,14 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
             };
             let mut err = struct_span_err!(resolver.session, span, E0432, "{}", msg);
             if let Some((_, p)) = name {
-                err.span_label(span, &p);
+                err.span_label(span, p);
             }
             err
         }
         ResolutionError::FailedToResolve(msg) => {
             let mut err = struct_span_err!(resolver.session, span, E0433,
                                            "failed to resolve. {}", msg);
-            err.span_label(span, &msg);
+            err.span_label(span, msg);
             err
         }
         ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
@@ -336,7 +336,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
                              span,
                              E0435,
                              "attempt to use a non-constant value in a constant");
-            err.span_label(span, &format!("non-constant used with constant"));
+            err.span_label(span, "non-constant used with constant");
             err
         }
         ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => {
@@ -345,9 +345,9 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
                                            span,
                                            E0530,
                                            "{}s cannot shadow {}s", what_binding, shadows_what);
-            err.span_label(span, &format!("cannot be named the same as a {}", shadows_what));
+            err.span_label(span, format!("cannot be named the same as a {}", shadows_what));
             let participle = if binding.is_import() { "imported" } else { "defined" };
-            let msg = &format!("a {} `{}` is {} here", shadows_what, name, participle);
+            let msg = format!("a {} `{}` is {} here", shadows_what, name, participle);
             err.span_label(binding.span, msg);
             err
         }
@@ -355,7 +355,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
             let mut err = struct_span_err!(resolver.session, span, E0128,
                                            "type parameters with a default cannot use \
                                             forward declared identifiers");
-            err.span_label(span, &format!("defaulted type parameters \
+            err.span_label(span, format!("defaulted type parameters \
                                            cannot be forward declared"));
             err
         }
@@ -2256,13 +2256,13 @@ impl<'a> Resolver<'a> {
             if is_self_type(path, ns) {
                 __diagnostic_used!(E0411);
                 err.code("E0411".into());
-                err.span_label(span, &format!("`Self` is only available in traits and impls"));
+                err.span_label(span, "`Self` is only available in traits and impls");
                 return err;
             }
             if is_self_value(path, ns) {
                 __diagnostic_used!(E0424);
                 err.code("E0424".into());
-                err.span_label(span, &format!("`self` value is only available in \
+                err.span_label(span, format!("`self` value is only available in \
                                                methods with `self` parameter"));
                 return err;
             }
@@ -2294,18 +2294,18 @@ impl<'a> Resolver<'a> {
                     let self_is_available = this.self_value_is_available(path[0].ctxt);
                     match candidate {
                         AssocSuggestion::Field => {
-                            err.span_label(span, &format!("did you mean `self.{}`?", path_str));
+                            err.span_label(span, format!("did you mean `self.{}`?", path_str));
                             if !self_is_available {
-                                err.span_label(span, &format!("`self` value is only available in \
+                                err.span_label(span, format!("`self` value is only available in \
                                                                methods with `self` parameter"));
                             }
                         }
                         AssocSuggestion::MethodWithSelf if self_is_available => {
-                            err.span_label(span, &format!("did you mean `self.{}(...)`?",
+                            err.span_label(span, format!("did you mean `self.{}(...)`?",
                                                            path_str));
                         }
                         AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => {
-                            err.span_label(span, &format!("did you mean `Self::{}`?", path_str));
+                            err.span_label(span, format!("did you mean `Self::{}`?", path_str));
                         }
                     }
                     return err;
@@ -2316,7 +2316,7 @@ impl<'a> Resolver<'a> {
 
             // Try Levenshtein.
             if let Some(candidate) = this.lookup_typo_candidate(path, ns, is_expected) {
-                err.span_label(ident_span, &format!("did you mean `{}`?", candidate));
+                err.span_label(ident_span, format!("did you mean `{}`?", candidate));
                 levenshtein_worked = true;
             }
 
@@ -2324,21 +2324,21 @@ impl<'a> Resolver<'a> {
             if let Some(def) = def {
                 match (def, source) {
                     (Def::Macro(..), _) => {
-                        err.span_label(span, &format!("did you mean `{}!(...)`?", path_str));
+                        err.span_label(span, format!("did you mean `{}!(...)`?", path_str));
                         return err;
                     }
                     (Def::TyAlias(..), PathSource::Trait) => {
-                        err.span_label(span, &format!("type aliases cannot be used for traits"));
+                        err.span_label(span, "type aliases cannot be used for traits");
                         return err;
                     }
                     (Def::Mod(..), PathSource::Expr(Some(parent))) => match parent.node {
                         ExprKind::Field(_, ident) => {
-                            err.span_label(parent.span, &format!("did you mean `{}::{}`?",
+                            err.span_label(parent.span, format!("did you mean `{}::{}`?",
                                                                  path_str, ident.node));
                             return err;
                         }
                         ExprKind::MethodCall(ident, ..) => {
-                            err.span_label(parent.span, &format!("did you mean `{}::{}(...)`?",
+                            err.span_label(parent.span, format!("did you mean `{}::{}(...)`?",
                                                                  path_str, ident.node));
                             return err;
                         }
@@ -2349,12 +2349,12 @@ impl<'a> Resolver<'a> {
                             if let Some((ctor_def, ctor_vis))
                                     = this.struct_constructors.get(&def_id).cloned() {
                                 if is_expected(ctor_def) && !this.is_accessible(ctor_vis) {
-                                    err.span_label(span, &format!("constructor is not visible \
+                                    err.span_label(span, format!("constructor is not visible \
                                                                    here due to private fields"));
                                 }
                             }
                         }
-                        err.span_label(span, &format!("did you mean `{} {{ /* fields */ }}`?",
+                        err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?",
                                                        path_str));
                         return err;
                     }
@@ -2364,7 +2364,7 @@ impl<'a> Resolver<'a> {
 
             // Fallback label.
             if !levenshtein_worked {
-                err.span_label(base_span, &fallback_label);
+                err.span_label(base_span, fallback_label);
             }
             err
         };
@@ -3374,9 +3374,9 @@ impl<'a> Resolver<'a> {
             },
         };
 
-        err.span_label(span, &format!("`{}` already {}", name, participle));
+        err.span_label(span, format!("`{}` already {}", name, participle));
         if old_binding.span != syntax_pos::DUMMY_SP {
-            err.span_label(old_binding.span, &format!("previous {} of `{}` here", noun, name));
+            err.span_label(old_binding.span, format!("previous {} of `{}` here", noun, name));
         }
         err.emit();
         self.name_already_seen.insert(name, span);
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 030e3936de9..106f421f39e 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -630,7 +630,7 @@ impl<'a> Resolver<'a> {
                     err.help(&format!("did you mean `{}`?", suggestion));
                 }
             } else {
-                err.help(&format!("have you added the `#[macro_use]` on the module/import?"));
+                err.help("have you added the `#[macro_use]` on the module/import?");
             }
         }
     }
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 43654c8ce6f..804e1ea740f 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -539,7 +539,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
                 Ok(binding) if !binding.is_importable() => {
                     let msg = format!("`{}` is not directly importable", target);
                     struct_span_err!(this.session, directive.span, E0253, "{}", &msg)
-                        .span_label(directive.span, &format!("cannot be imported directly"))
+                        .span_label(directive.span, "cannot be imported directly")
                         .emit();
                     // Do not import this illegal binding. Import a dummy binding and pretend
                     // everything is fine
@@ -701,7 +701,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
             } else if ns == TypeNS {
                 struct_span_err!(self.session, directive.span, E0365,
                                  "`{}` is private, and cannot be reexported", ident)
-                    .span_label(directive.span, &format!("reexport of private `{}`", ident))
+                    .span_label(directive.span, format!("reexport of private `{}`", ident))
                     .note(&format!("consider declaring type or module `{}` with `pub`", ident))
                     .emit();
             } else {
@@ -794,7 +794,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
                             let msg =
                                 format!("a macro named `{}` has already been exported", ident);
                             self.session.struct_span_err(span, &msg)
-                                .span_label(span, &format!("`{}` already exported", ident))
+                                .span_label(span, format!("`{}` already exported", ident))
                                 .span_note(binding.span, "previous macro export here")
                                 .emit();
                         }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 33b0aa3dbff..adcb3d682ca 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -163,7 +163,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             hir::ParenthesizedParameters(..) => {
                 struct_span_err!(tcx.sess, span, E0214,
                           "parenthesized parameters may only be used with a trait")
-                    .span_label(span, &format!("only traits may use parentheses"))
+                    .span_label(span, "only traits may use parentheses")
                     .emit();
 
                 return Substs::for_item(tcx, def_id, |_, _| {
@@ -294,7 +294,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                     struct_span_err!(tcx.sess, span, E0393,
                                      "the type parameter `{}` must be explicitly specified",
                                      def.name)
-                        .span_label(span, &format!("missing reference to `{}`", def.name))
+                        .span_label(span, format!("missing reference to `{}`", def.name))
                         .note(&format!("because of the default `Self` reference, \
                                         type parameters must be specified on object types"))
                         .emit();
@@ -635,7 +635,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             let span = b.trait_ref.path.span;
             struct_span_err!(self.tcx().sess, span, E0225,
                 "only Send/Sync traits can be used as additional traits in a trait object")
-                .span_label(span, &format!("non-Send/Sync additional trait"))
+                .span_label(span, "non-Send/Sync additional trait")
                 .emit();
         }
 
@@ -684,7 +684,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 "the value of the associated type `{}` (from the trait `{}`) must be specified",
                         name,
                         tcx.item_path_str(trait_def_id))
-                        .span_label(span, &format!(
+                        .span_label(span, format!(
                             "missing associated type `{}` value", name))
                         .emit();
         }
@@ -730,7 +730,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                         trait_str: &str,
                                         name: &str) {
         struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type")
-            .span_label(span, &format!("ambiguous associated type"))
+            .span_label(span, "ambiguous associated type")
             .note(&format!("specify the type using the syntax `<{} as {}>::{}`",
                   type_str, trait_str, name))
             .emit();
@@ -784,7 +784,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                           "associated type `{}` not found for `{}`",
                           assoc_name,
                           ty_param_name)
-                  .span_label(span, &format!("associated type `{}` not found", assoc_name))
+                  .span_label(span, format!("associated type `{}` not found", assoc_name))
                   .emit();
                 return Err(ErrorReported);
             }
@@ -797,7 +797,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 "ambiguous associated type `{}` in bounds of `{}`",
                 assoc_name,
                 ty_param_name);
-            err.span_label(span, &format!("ambiguous associated type `{}`", assoc_name));
+            err.span_label(span, format!("ambiguous associated type `{}`", assoc_name));
 
             for bound in bounds {
                 let bound_span = self.tcx().associated_items(bound.def_id()).find(|item| {
@@ -806,7 +806,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 .and_then(|item| self.tcx().hir.span_if_local(item.def_id));
 
                 if let Some(span) = bound_span {
-                    err.span_label(span, &format!("ambiguous `{}` from `{}`",
+                    err.span_label(span, format!("ambiguous `{}` from `{}`",
                                                   assoc_name,
                                                   bound));
                 } else {
@@ -951,7 +951,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             for typ in segment.parameters.types() {
                 struct_span_err!(self.tcx().sess, typ.span, E0109,
                                  "type parameters are not allowed on this type")
-                    .span_label(typ.span, &format!("type parameter not allowed"))
+                    .span_label(typ.span, "type parameter not allowed")
                     .emit();
                 break;
             }
@@ -959,7 +959,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 struct_span_err!(self.tcx().sess, lifetime.span, E0110,
                                  "lifetime parameters are not allowed on this type")
                     .span_label(lifetime.span,
-                                &format!("lifetime parameter not allowed on this type"))
+                                "lifetime parameter not allowed on this type")
                     .emit();
                 break;
             }
@@ -973,7 +973,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     pub fn prohibit_projection(&self, span: Span) {
         let mut err = struct_span_err!(self.tcx().sess, span, E0229,
                                        "associated type bindings are not allowed here");
-        err.span_label(span, &format!("associate type not allowed here")).emit();
+        err.span_label(span, "associate type not allowed here").emit();
     }
 
     // Check a type Path and convert it to a Ty.
@@ -1214,7 +1214,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             hir::TyTypeof(ref _e) => {
                 struct_span_err!(tcx.sess, ast_ty.span, E0516,
                                  "`typeof` is a reserved keyword but unimplemented")
-                    .span_label(ast_ty.span, &format!("reserved keyword"))
+                    .span_label(ast_ty.span, "reserved keyword")
                     .emit();
 
                 tcx.types.err
@@ -1426,7 +1426,7 @@ fn check_type_argument_count(tcx: TyCtxt, span: Span, supplied: usize,
                 "wrong number of type arguments: {} {}, found {}",
                 expected, required, supplied)
             .span_label(span,
-                &format!("{} {} type argument{}",
+                format!("{} {} type argument{}",
                     expected,
                     required,
                     arguments_plural))
@@ -1444,7 +1444,7 @@ fn check_type_argument_count(tcx: TyCtxt, span: Span, supplied: usize,
                 expected, supplied)
             .span_label(
                 span,
-                &format!("{} type argument{}",
+                format!("{} type argument{}",
                     if accepted == 0 { "expected no" } else { &expected },
                     arguments_plural)
             )
@@ -1470,7 +1470,7 @@ fn report_lifetime_number_error(tcx: TyCtxt, span: Span, number: usize, expected
     struct_span_err!(tcx.sess, span, E0107,
                      "wrong number of lifetime parameters: expected {}, found {}",
                      expected, number)
-        .span_label(span, &label)
+        .span_label(span, label)
         .emit();
 }
 
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index ac10dfd36e2..bbe34f37950 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -97,7 +97,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                     struct_span_err!(tcx.sess, span, E0029,
                         "only char and numeric types are allowed in range patterns")
-                        .span_label(span, &format!("ranges require char or numeric types"))
+                        .span_label(span, "ranges require char or numeric types")
                         .note(&format!("start type: {}", self.ty_to_string(lhs_ty)))
                         .note(&format!("end type: {}", self.ty_to_string(rhs_ty)))
                         .emit();
@@ -263,7 +263,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                     tcx.sess, pat.span, E0527,
                                     "pattern requires {} elements but array has {}",
                                     min_len, size)
-                                    .span_label(pat.span, &format!("expected {} elements",size))
+                                    .span_label(pat.span, format!("expected {} elements",size))
                                     .emit();
                             }
                             (inner_ty, tcx.types.err)
@@ -274,7 +274,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                     "pattern requires at least {} elements but array has {}",
                                     min_len, size)
                                 .span_label(pat.span,
-                                    &format!("pattern cannot match array of {} elements", size))
+                                    format!("pattern cannot match array of {} elements", size))
                                 .emit();
                             (inner_ty, tcx.types.err)
                         }
@@ -297,7 +297,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             }
 
                             err.span_label( pat.span,
-                                &format!("pattern cannot match with input type `{}`", expected_ty)
+                                format!("pattern cannot match with input type `{}`", expected_ty)
                             ).emit();
                         }
                         (tcx.types.err, tcx.types.err)
@@ -379,7 +379,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     let type_str = self.ty_to_string(expected);
                     struct_span_err!(self.tcx.sess, span, E0033,
                               "type `{}` cannot be dereferenced", type_str)
-                        .span_label(span, &format!("type `{}` cannot be dereferenced", type_str))
+                        .span_label(span, format!("type `{}` cannot be dereferenced", type_str))
                         .emit();
                     return false
                 }
@@ -593,7 +593,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               def.kind_name(),
                               hir::print::to_string(&tcx.hir, |s| s.print_qpath(qpath, false)));
             struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg)
-                .span_label(pat.span, &format!("not a tuple variant or struct")).emit();
+                .span_label(pat.span, "not a tuple variant or struct").emit();
             on_error();
         };
 
@@ -642,7 +642,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                              "this pattern has {} field{}, but the corresponding {} has {} field{}",
                              subpats.len(), subpats_ending, def.kind_name(),
                              variant.fields.len(),  fields_ending)
-                .span_label(pat.span, &format!("expected {} field{}, found {}",
+                .span_label(pat.span, format!("expected {} field{}, found {}",
                                                variant.fields.len(), fields_ending, subpats.len()))
                 .emit();
             on_error();
@@ -683,8 +683,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                       in the pattern",
                                      field.name)
                         .span_label(span,
-                                    &format!("multiple uses of `{}` in pattern", field.name))
-                        .span_label(*occupied.get(), &format!("first use of `{}`", field.name))
+                                    format!("multiple uses of `{}` in pattern", field.name))
+                        .span_label(*occupied.get(), format!("first use of `{}`", field.name))
                         .emit();
                     tcx.types.err
                 }
@@ -703,7 +703,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                              tcx.item_path_str(variant.did),
                                              field.name)
                                 .span_label(span,
-                                            &format!("{} `{}` does not have field `{}`",
+                                            format!("{} `{}` does not have field `{}`",
                                                      kind_name,
                                                      tcx.item_path_str(variant.did),
                                                      field.name))
@@ -732,7 +732,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 struct_span_err!(tcx.sess, span, E0027,
                                 "pattern does not mention field `{}`",
                                 field.name)
-                                .span_label(span, &format!("missing field `{}`", field.name))
+                                .span_label(span, format!("missing field `{}`", field.name))
                                 .emit();
             }
         }
diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs
index c9584f1d9e1..f03451c04ed 100644
--- a/src/librustc_typeck/check/autoderef.rs
+++ b/src/librustc_typeck/check/autoderef.rs
@@ -62,7 +62,7 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
                              E0055,
                              "reached the recursion limit while auto-dereferencing {:?}",
                              self.cur_ty)
-                .span_label(self.span, &format!("deref recursion limit reached"))
+                .span_label(self.span, "deref recursion limit reached")
                 .help(&format!(
                         "consider adding a `#[recursion_limit=\"{}\"]` attribute to your crate",
                         suggested_limit))
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 7a49309e005..dde5f598a68 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -27,7 +27,7 @@ use rustc::hir;
 pub fn check_legal_trait_for_method_call(tcx: TyCtxt, span: Span, trait_id: DefId) {
     if tcx.lang_items.drop_trait() == Some(trait_id) {
         struct_span_err!(tcx.sess, span, E0040, "explicit use of destructor method")
-            .span_label(span, &format!("explicit destructor calls not allowed"))
+            .span_label(span, "explicit destructor calls not allowed")
             .emit();
     }
 }
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 32b363ed755..72ce7d3b5ed 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -155,7 +155,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
                                        },
                                        self.expr_ty);
                 err.span_label(error_span,
-                               &format!("cannot cast `{}` as `{}`",
+                               format!("cannot cast `{}` as `{}`",
                                         fcx.ty_to_string(self.expr_ty),
                                         cast_ty));
                 if let Ok(snippet) = fcx.sess().codemap().span_to_snippet(self.expr.span) {
@@ -200,7 +200,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
             }
             CastError::CastToBool => {
                 struct_span_err!(fcx.tcx.sess, self.span, E0054, "cannot cast as `bool`")
-                    .span_label(self.span, &format!("unsupported cast"))
+                    .span_label(self.span, "unsupported cast")
                     .help("compare with zero instead")
                     .emit();
             }
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index b0b57aee5b2..c228fc6b24a 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -1144,7 +1144,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
                         db = struct_span_err!(
                             fcx.tcx.sess, cause.span, E0069,
                             "`return;` in a function whose return type is not `()`");
-                        db.span_label(cause.span, &format!("return type is not ()"));
+                        db.span_label(cause.span, "return type is not ()");
                     }
                     _ => {
                         db = fcx.report_mismatched_types(cause, expected, found, err);
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 9ed5528e867..0579bb15fd6 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -402,7 +402,7 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          "lifetime parameters or bounds on method `{}` do not match the \
                           trait declaration",
                          impl_m.name)
-            .span_label(span, &format!("lifetimes do not match trait"))
+            .span_label(span, "lifetimes do not match trait")
             .emit();
         return Err(ErrorReported);
     }
@@ -534,9 +534,9 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                             not in the trait",
                                            trait_m.name,
                                            self_descr);
-            err.span_label(impl_m_span, &format!("`{}` used in impl", self_descr));
+            err.span_label(impl_m_span, format!("`{}` used in impl", self_descr));
             if let Some(span) = tcx.hir.span_if_local(trait_m.def_id) {
-                err.span_label(span, &format!("trait declared without `{}`", self_descr));
+                err.span_label(span, format!("trait declared without `{}`", self_descr));
             }
             err.emit();
             return Err(ErrorReported);
@@ -552,9 +552,9 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                            trait_m.name,
                                            self_descr);
             err.span_label(impl_m_span,
-                           &format!("expected `{}` in impl", self_descr));
+                           format!("expected `{}` in impl", self_descr));
             if let Some(span) = tcx.hir.span_if_local(trait_m.def_id) {
-                err.span_label(span, &format!("`{}` used in trait", self_descr));
+                err.span_label(span, format!("`{}` used in trait", self_descr));
             }
             err.emit();
             return Err(ErrorReported);
@@ -606,7 +606,7 @@ fn compare_number_of_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
         if let Some(span) = trait_item_span {
             err.span_label(span,
-                           &format!("expected {}",
+                           format!("expected {}",
                                     &if num_trait_m_type_params != 1 {
                                         format!("{} type parameters", num_trait_m_type_params)
                                     } else {
@@ -617,7 +617,7 @@ fn compare_number_of_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
 
         err.span_label(span,
-                       &format!("found {}{}",
+                       format!("found {}{}",
                                 &if num_impl_m_type_params != 1 {
                                     format!("{} type parameters", num_impl_m_type_params)
                                 } else {
@@ -696,7 +696,7 @@ fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                        trait_number_args);
         if let Some(trait_span) = trait_span {
             err.span_label(trait_span,
-                           &format!("trait requires {}",
+                           format!("trait requires {}",
                                     &if trait_number_args != 1 {
                                         format!("{} parameters", trait_number_args)
                                     } else {
@@ -704,7 +704,7 @@ fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     }));
         }
         err.span_label(impl_span,
-                       &format!("expected {}, found {}",
+                       format!("expected {}, found {}",
                                 &if trait_number_args != 1 {
                                     format!("{} parameters", trait_number_args)
                                 } else {
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 2a97bc1d98f..60067e6a6ec 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -57,7 +57,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         "intrinsic has wrong number of type \
                         parameters: found {}, expected {}",
                         i_n_tps, n_tps)
-            .span_label(span, &format!("expected {} type parameter", n_tps))
+            .span_label(span, format!("expected {} type parameter", n_tps))
             .emit();
     } else {
         require_same_types(tcx,
@@ -101,7 +101,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             op => {
                 struct_span_err!(tcx.sess, it.span, E0092,
                       "unrecognized atomic operation function: `{}`", op)
-                  .span_label(it.span, &format!("unrecognized atomic operation"))
+                  .span_label(it.span, "unrecognized atomic operation")
                   .emit();
                 return;
             }
@@ -305,7 +305,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 struct_span_err!(tcx.sess, it.span, E0093,
                                 "unrecognized intrinsic function: `{}`",
                                 *other)
-                                .span_label(it.span, &format!("unrecognized intrinsic"))
+                                .span_label(it.span, "unrecognized intrinsic")
                                 .emit();
                 return;
             }
@@ -505,7 +505,7 @@ fn match_intrinsic_type_to_type<'a, 'tcx>(
                     }
                 }
                 _ => simple_error(&format!("`{}`", t),
-                                  &format!("tuple")),
+                                  "tuple"),
             }
         }
     }
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index aad14bc975d..fdde4e9fef4 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -285,7 +285,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                                  self.span,
                                  E0035,
                                  "does not take type parameters")
-                    .span_label(self.span, &"called with unneeded type parameters")
+                    .span_label(self.span, "called with unneeded type parameters")
                     .emit();
             } else {
                 struct_span_err!(self.tcx.sess,
@@ -296,7 +296,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                                  num_method_types,
                                  num_supplied_types)
                     .span_label(self.span,
-                                &format!("Passed {} type argument{}, expected {}",
+                                format!("Passed {} type argument{}, expected {}",
                                          num_supplied_types,
                                          if num_supplied_types != 1 { "s" } else { "" },
                                          num_method_types))
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 4b975d7b324..c7ec379b0de 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -209,9 +209,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                               expr_string,
                                                               item_name));
                                         }
-                                        err.span_label(span, &"field, not a method");
+                                        err.span_label(span, "field, not a method");
                                     } else {
-                                        err.span_label(span, &"private field, not a method");
+                                        err.span_label(span, "private field, not a method");
                                     }
                                     break;
                                 }
@@ -272,7 +272,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                span,
                                                E0034,
                                                "multiple applicable items in scope");
-                err.span_label(span, &format!("multiple `{}` found", item_name));
+                err.span_label(span, format!("multiple `{}` found", item_name));
 
                 report_candidates(&mut err, sources);
                 err.emit();
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 2e29aeeb022..127ffc60cf4 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1130,7 +1130,7 @@ fn check_on_unimplemented<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             struct_span_err!(
                 tcx.sess, attr.span, E0232,
                 "this attribute must have a value")
-                .span_label(attr.span, &format!("attribute requires a value"))
+                .span_label(attr.span, "attribute requires a value")
                 .note(&format!("eg `#[rustc_on_unimplemented = \"foo\"]`"))
                 .emit();
         }
@@ -1146,12 +1146,12 @@ fn report_forbidden_specialization<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         "`{}` specializes an item from a parent `impl`, but \
          that item is not marked `default`",
         impl_item.name);
-    err.span_label(impl_item.span, &format!("cannot specialize default item `{}`",
+    err.span_label(impl_item.span, format!("cannot specialize default item `{}`",
                                             impl_item.name));
 
     match tcx.span_of_impl(parent_impl) {
         Ok(span) => {
-            err.span_label(span, &"parent `impl` is here");
+            err.span_label(span, "parent `impl` is here");
             err.note(&format!("to specialize, `{}` in the parent `impl` must be marked `default`",
                               impl_item.name));
         }
@@ -1226,11 +1226,11 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   which doesn't match its trait `{}`",
                                   ty_impl_item.name,
                                   impl_trait_ref);
-                         err.span_label(impl_item.span, &format!("does not match trait"));
+                         err.span_label(impl_item.span, "does not match trait");
                          // We can only get the spans from local trait definition
                          // Same for E0324 and E0325
                          if let Some(trait_span) = tcx.hir.span_if_local(ty_trait_item.def_id) {
-                            err.span_label(trait_span, &format!("item in trait"));
+                            err.span_label(trait_span, "item in trait");
                          }
                          err.emit()
                     }
@@ -1262,9 +1262,9 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   which doesn't match its trait `{}`",
                                   ty_impl_item.name,
                                   impl_trait_ref);
-                         err.span_label(impl_item.span, &format!("does not match trait"));
+                         err.span_label(impl_item.span, "does not match trait");
                          if let Some(trait_span) = tcx.hir.span_if_local(ty_trait_item.def_id) {
-                            err.span_label(trait_span, &format!("item in trait"));
+                            err.span_label(trait_span, "item in trait");
                          }
                          err.emit()
                     }
@@ -1280,9 +1280,9 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   which doesn't match its trait `{}`",
                                   ty_impl_item.name,
                                   impl_trait_ref);
-                         err.span_label(impl_item.span, &format!("does not match trait"));
+                         err.span_label(impl_item.span, "does not match trait");
                          if let Some(trait_span) = tcx.hir.span_if_local(ty_trait_item.def_id) {
-                            err.span_label(trait_span, &format!("item in trait"));
+                            err.span_label(trait_span, "item in trait");
                          }
                          err.emit()
                     }
@@ -1331,13 +1331,13 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             missing_items.iter()
                   .map(|trait_item| trait_item.name.to_string())
                   .collect::>().join("`, `"));
-        err.span_label(impl_span, &format!("missing `{}` in implementation",
+        err.span_label(impl_span, format!("missing `{}` in implementation",
                 missing_items.iter()
                     .map(|trait_item| trait_item.name.to_string())
                     .collect::>().join("`, `")));
         for trait_item in missing_items {
             if let Some(span) = tcx.hir.span_if_local(trait_item.def_id) {
-                err.span_label(span, &format!("`{}` from trait", trait_item.name));
+                err.span_label(span, format!("`{}` from trait", trait_item.name));
             } else {
                 err.note(&format!("`{}` from trait: `{}`",
                                   trait_item.name,
@@ -1377,7 +1377,7 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         Representability::SelfRecursive(spans) => {
             let mut err = tcx.recursive_type_with_infinite_size_error(item_def_id);
             for span in spans {
-                err.span_label(span, &"recursive without indirection");
+                err.span_label(span, "recursive without indirection");
             }
             err.emit();
             return false
@@ -1399,7 +1399,7 @@ pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId
             let e = fields[0].ty(tcx, substs);
             if !fields.iter().all(|f| f.ty(tcx, substs) == e) {
                 struct_span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous")
-                                .span_label(sp, &format!("SIMD elements must have the same type"))
+                                .span_label(sp, "SIMD elements must have the same type")
                                 .emit();
                 return;
             }
@@ -1471,7 +1471,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         struct_span_err!(
             tcx.sess, sp, E0084,
             "unsupported representation for zero-variant enum")
-            .span_label(sp, &format!("unsupported enum representation"))
+            .span_label(sp, "unsupported enum representation")
             .emit();
     }
 
@@ -1505,8 +1505,8 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             };
             struct_span_err!(tcx.sess, span, E0081,
                              "discriminant value `{}` already exists", disr_vals[i])
-                .span_label(i_span, &format!("first use of `{}`", disr_vals[i]))
-                .span_label(span , &format!("enum already has `{}`", disr_vals[i]))
+                .span_label(i_span, format!("first use of `{}`", disr_vals[i]))
+                .span_label(span , format!("enum already has `{}`", disr_vals[i]))
                 .emit();
         }
         disr_vals.push(discr);
@@ -2401,12 +2401,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     if arg_count == 1 {" was"} else {"s were"}),
                 error_code);
 
-            err.span_label(sp, &format!("expected {}{} parameter{}",
+            err.span_label(sp, format!("expected {}{} parameter{}",
                                         if variadic {"at least "} else {""},
                                         expected_count,
                                         if expected_count == 1 {""} else {"s"}));
             if let Some(def_s) = def_span {
-                err.span_label(def_s, &format!("defined here"));
+                err.span_label(def_s, "defined here");
             }
             err.emit();
         }
@@ -2938,10 +2938,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     if let Some(suggested_field_name) =
                         Self::suggest_field_name(def.struct_variant(), field, vec![]) {
                             err.span_label(field.span,
-                                           &format!("did you mean `{}`?", suggested_field_name));
+                                           format!("did you mean `{}`?", suggested_field_name));
                         } else {
                             err.span_label(field.span,
-                                           &format!("unknown field"));
+                                           "unknown field");
                         };
                 }
                 ty::TyRawPtr(..) => {
@@ -3076,15 +3076,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                            &field.name,
                                                            skip_fields.collect()) {
             err.span_label(field.name.span,
-                           &format!("field does not exist - did you mean `{}`?", field_name));
+                           format!("field does not exist - did you mean `{}`?", field_name));
         } else {
             match ty.sty {
                 ty::TyAdt(adt, ..) if adt.is_enum() => {
-                    err.span_label(field.name.span, &format!("`{}::{}` does not have this field",
+                    err.span_label(field.name.span, format!("`{}::{}` does not have this field",
                                                              ty, variant.name));
                 }
                 _ => {
-                    err.span_label(field.name.span, &format!("`{}` does not have this field", ty));
+                    err.span_label(field.name.span, format!("`{}` does not have this field", ty));
                 }
             }
         };
@@ -3149,10 +3149,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                 "field `{}` specified more than once",
                                                 field.name.node);
 
-                    err.span_label(field.name.span, &format!("used more than once"));
+                    err.span_label(field.name.span, "used more than once");
 
                     if let Some(prev_span) = seen_fields.get(&field.name.node) {
-                        err.span_label(*prev_span, &format!("first use of `{}`", field.name.node));
+                        err.span_label(*prev_span, format!("first use of `{}`", field.name.node));
                     }
 
                     err.emit();
@@ -3199,7 +3199,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         remaining_fields_names,
                         truncated_fields_error,
                         adt_ty)
-                        .span_label(span, &format!("missing {}{}",
+                        .span_label(span, format!("missing {}{}",
                             remaining_fields_names,
                             truncated_fields_error))
                         .emit();
@@ -3266,7 +3266,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             struct_span_err!(self.tcx.sess, path_span, E0071,
                              "expected struct, variant or union type, found {}",
                              ty.sort_string(self.tcx))
-                .span_label(path_span, &format!("not a struct"))
+                .span_label(path_span, "not a struct")
                 .emit();
             None
         }
@@ -3625,7 +3625,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     "invalid left-hand side expression")
                 .span_label(
                     expr.span,
-                    &format!("left-hand of expression not valid"))
+                    "left-hand of expression not valid")
                 .emit();
             }
 
@@ -4517,7 +4517,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                              "too many lifetime parameters provided: \
                               expected at most {}, found {}",
                              expected_text, actual_text)
-                .span_label(span, &format!("expected {}", expected_text))
+                .span_label(span, format!("expected {}", expected_text))
                 .emit();
         } else if lifetimes.len() > 0 && lifetimes.len() < lifetime_defs.len() {
             let expected_text = count_lifetime_params(lifetime_defs.len());
@@ -4526,7 +4526,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                              "too few lifetime parameters provided: \
                               expected {}, found {}",
                              expected_text, actual_text)
-                .span_label(span, &format!("expected {}", expected_text))
+                .span_label(span, format!("expected {}", expected_text))
                 .emit();
         }
 
@@ -4551,7 +4551,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                              "too many type parameters provided: \
                               expected at most {}, found {}",
                              expected_text, actual_text)
-                .span_label(span, &format!("expected {}", expected_text))
+                .span_label(span, format!("expected {}", expected_text))
                 .emit();
 
             // To prevent derived errors to accumulate due to extra
@@ -4565,7 +4565,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                              "too few type parameters provided: \
                               expected {}, found {}",
                              expected_text, actual_text)
-                .span_label(span, &format!("expected {}", expected_text))
+                .span_label(span, format!("expected {}", expected_text))
                 .emit();
         }
 
@@ -4654,7 +4654,7 @@ pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             struct_span_err!(tcx.sess, param.span, E0091,
                 "type parameter `{}` is unused",
                 param.name)
-                .span_label(param.span, &format!("unused type parameter"))
+                .span_label(param.span, "unused type parameter")
                 .emit();
         }
     }
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index d3d65ce4a62..59cb61d9b97 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -50,7 +50,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 E0067, "invalid left-hand side expression")
             .span_label(
                 lhs_expr.span,
-                &format!("invalid expression for left-hand side"))
+                "invalid expression for left-hand side")
             .emit();
         }
         ty
@@ -203,7 +203,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                          op.node.as_str(),
                                          lhs_ty)
                             .span_label(lhs_expr.span,
-                                        &format!("cannot use `{}=` on type `{}`",
+                                        format!("cannot use `{}=` on type `{}`",
                                         op.node.as_str(), lhs_ty))
                             .emit();
                     } else {
@@ -278,7 +278,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             if let TyRef(_, r_ty) = rhs_ty.sty {
                 if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr {
                     err.span_label(expr.span,
-                        &"`+` can't be used to concatenate two `&str` strings");
+                        "`+` can't be used to concatenate two `&str` strings");
                     let codemap = self.tcx.sess.codemap();
                     let suggestion =
                         match codemap.span_to_snippet(lhs_expr.span) {
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 1887eaef360..93529aecac0 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -684,7 +684,7 @@ fn error_392<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, param_name: ast:
                        -> DiagnosticBuilder<'tcx> {
     let mut err = struct_span_err!(tcx.sess, span, E0392,
                   "parameter `{}` is never used", param_name);
-    err.span_label(span, &format!("unused type parameter"));
+    err.span_label(span, "unused type parameter");
     err
 }
 
@@ -692,7 +692,7 @@ fn error_194(tcx: TyCtxt, span: Span, trait_decl_span: Span, name: ast::Name) {
     struct_span_err!(tcx.sess, span, E0194,
               "type parameter `{}` shadows another type parameter of the same name",
               name)
-        .span_label(span, &format!("shadows another type parameter"))
-        .span_label(trait_decl_span, &format!("first `{}` declared here", name))
+        .span_label(span, "shadows another type parameter")
+        .span_label(trait_decl_span, format!("first `{}` declared here", name))
         .emit();
 }
diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs
index 49785d8850f..743bfbb44ab 100644
--- a/src/librustc_typeck/coherence/builtin.rs
+++ b/src/librustc_typeck/coherence/builtin.rs
@@ -74,7 +74,7 @@ fn visit_implementation_of_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                          E0120,
                                          "the Drop trait may only be implemented on \
                                          structures")
-                            .span_label(span, &format!("implementing Drop requires a struct"))
+                            .span_label(span, "implementing Drop requires a struct")
                             .emit();
                     }
                     _ => {
@@ -130,7 +130,7 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              "the trait `Copy` may not be implemented for this type")
                 .span_label(
                     tcx.def_span(field.did),
-                    &"this field does not implement `Copy`")
+                    "this field does not implement `Copy`")
                 .emit()
         }
         Err(CopyImplementationError::NotAnAdt) => {
@@ -145,7 +145,7 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              span,
                              E0206,
                              "the trait `Copy` may not be implemented for this type")
-                .span_label(span, &format!("type is not a structure or enumeration"))
+                .span_label(span, "type is not a structure or enumeration")
                 .emit();
         }
         Err(CopyImplementationError::HasDestructor) => {
@@ -154,7 +154,7 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              E0184,
                              "the trait `Copy` may not be implemented for this type; the \
                               type has a destructor")
-                .span_label(span, &format!("Copy not allowed on types with destructors"))
+                .span_label(span, "Copy not allowed on types with destructors")
                 .emit();
         }
     }
@@ -310,7 +310,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                           })
                                           .collect::>()
                                           .join(", ")));
-                    err.span_label(span, &format!("requires multiple coercions"));
+                    err.span_label(span, "requires multiple coercions");
                     err.emit();
                     return err_info;
                 }
diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs
index 238952865c7..f7ebc210442 100644
--- a/src/librustc_typeck/coherence/inherent_impls.rs
+++ b/src/librustc_typeck/coherence/inherent_impls.rs
@@ -259,7 +259,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
                                  ty.span,
                                  E0118,
                                  "no base type found for inherent implementation")
-                    .span_label(ty.span, &format!("impl requires a base type"))
+                    .span_label(ty.span, "impl requires a base type")
                     .note(&format!("either implement a trait on it or create a newtype \
                                     to wrap it instead"))
                     .emit();
@@ -296,7 +296,7 @@ impl<'a, 'tcx> InherentCollect<'a, 'tcx> {
                              "cannot define inherent `impl` for a type outside of the crate \
                               where the type is defined")
                 .span_label(item.span,
-                            &format!("impl for type defined outside of crate."))
+                            "impl for type defined outside of crate.")
                 .note("define and implement a trait or new type instead")
                 .emit();
         }
diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs
index 34aec8ef1ac..2751e1ff38a 100644
--- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs
+++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs
@@ -56,9 +56,9 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
                                      "duplicate definitions with name `{}`",
                                      name)
                         .span_label(self.tcx.span_of_impl(item1).unwrap(),
-                                    &format!("duplicate definitions for `{}`", name))
+                                    format!("duplicate definitions for `{}`", name))
                         .span_label(self.tcx.span_of_impl(item2).unwrap(),
-                                    &format!("other definition for `{}`", name))
+                                    format!("other definition for `{}`", name))
                         .emit();
                 }
             }
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 56ae9d54575..8b9dc20315d 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -62,7 +62,7 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d
                          span,
                          E0322,
                          "explicit impls for the `Sized` trait are not permitted")
-            .span_label(span, &format!("impl of 'Sized' not allowed"))
+            .span_label(span, "impl of 'Sized' not allowed")
             .emit();
         return;
     }
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index 8ded3003c78..097720adad4 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -48,7 +48,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
                                          E0117,
                                          "only traits defined in the current crate can be \
                                           implemented for arbitrary types")
-                            .span_label(item.span, &format!("impl doesn't use types inside crate"))
+                            .span_label(item.span, "impl doesn't use types inside crate")
                             .note(&format!("the impl does not reference any types defined in \
                                             this crate"))
                             .note("define and implement a trait or new type instead")
@@ -153,7 +153,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
                                      "cannot create default implementations for traits outside \
                                       the crate they're defined in; define a new trait instead")
                         .span_label(item_trait_ref.path.span,
-                                    &format!("`{}` trait not defined in this crate",
+                                    format!("`{}` trait not defined in this crate",
                             self.tcx.hir.node_to_pretty_string(item_trait_ref.ref_id)))
                         .emit();
                     return;
diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs
index 383a9e0e695..f479dc2e6ab 100644
--- a/src/librustc_typeck/coherence/overlap.rs
+++ b/src/librustc_typeck/coherence/overlap.rs
@@ -60,9 +60,9 @@ pub fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) {
 
         match tcx.span_of_impl(overlap.with_impl) {
             Ok(span) => {
-                err.span_label(span, &format!("first implementation here"));
+                err.span_label(span, "first implementation here");
                 err.span_label(tcx.span_of_impl(impl_def_id).unwrap(),
-                               &format!("conflicting implementation{}",
+                               format!("conflicting implementation{}",
                                         overlap.self_desc
                                             .map_or(String::new(),
                                                     |ty| format!(" for `{}`", ty))));
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index f44f74830cb..ec200241ee6 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -220,7 +220,7 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
             span,
             E0121,
             "the type placeholder `_` is not allowed within types on item signatures"
-        ).span_label(span, &format!("not allowed in type signatures"))
+        ).span_label(span, "not allowed in type signatures")
         .emit();
         self.tcx().types.err
     }
@@ -568,7 +568,7 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         } else {
             struct_span_err!(tcx.sess, variant.span, E0370,
                              "enum discriminant overflowed")
-                .span_label(variant.span, &format!("overflowed on value after {}",
+                .span_label(variant.span, format!("overflowed on value after {}",
                                                    prev_discr.unwrap()))
                 .note(&format!("explicitly set `{} = {}` if that is desired outcome",
                                variant.node.name, wrapped_discr))
@@ -604,8 +604,8 @@ fn convert_struct_variant<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             struct_span_err!(tcx.sess, f.span, E0124,
                              "field `{}` is already declared",
                              f.name)
-                .span_label(f.span, &"field already declared")
-                .span_label(prev_span, &format!("`{}` first declared here", f.name))
+                .span_label(f.span, "field already declared")
+                .span_label(prev_span, format!("`{}` first declared here", f.name))
                 .emit();
         } else {
             seen_fields.insert(f.name, f.span);
diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs
index 1c44572fbb4..6b4f08d3d4c 100644
--- a/src/librustc_typeck/impl_wf_check.rs
+++ b/src/librustc_typeck/impl_wf_check.rs
@@ -166,7 +166,7 @@ fn report_unused_parameter(tcx: TyCtxt,
         "the {} parameter `{}` is not constrained by the \
         impl trait, self type, or predicates",
         kind, name)
-        .span_label(span, &format!("unconstrained {} parameter", kind))
+        .span_label(span, format!("unconstrained {} parameter", kind))
         .emit();
 }
 
@@ -188,9 +188,9 @@ fn enforce_impl_items_are_distinct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                "duplicate definitions with name `{}`:",
                                                impl_item.name);
                 err.span_label(*entry.get(),
-                               &format!("previous definition of `{}` here",
+                               format!("previous definition of `{}` here",
                                         impl_item.name));
-                err.span_label(impl_item.span, &format!("duplicate definition"));
+                err.span_label(impl_item.span, "duplicate definition");
                 err.emit();
             }
             Vacant(entry) => {
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index c1456e79782..84de4ff2b7b 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -143,7 +143,7 @@ fn require_c_abi_if_variadic(tcx: TyCtxt,
     if decl.variadic && abi != Abi::C {
         let mut err = struct_span_err!(tcx.sess, span, E0045,
                   "variadic function must have C calling convention");
-        err.span_label(span, &("variadics require C calling conventions").to_string())
+        err.span_label(span, "variadics require C calling conventions")
             .emit();
     }
 }
@@ -190,7 +190,7 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 struct_span_err!(tcx.sess, generics.span, E0131,
                                          "main function is not allowed to have type parameters")
                                     .span_label(generics.span,
-                                                &format!("main cannot have type parameters"))
+                                                "main cannot have type parameters")
                                     .emit();
                                 return;
                             }
@@ -240,7 +240,7 @@ fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             struct_span_err!(tcx.sess, ps.span, E0132,
                                 "start function is not allowed to have type parameters")
                                 .span_label(ps.span,
-                                            &format!("start function cannot have type parameters"))
+                                            "start function cannot have type parameters")
                                 .emit();
                             return;
                         }
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 0f47265a1aa..5db82e23bbf 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -687,9 +687,9 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool,
             }
         }
         clean::Vector(ref t) if is_not_debug => {
-            primitive_link(f, PrimitiveType::Slice, &format!("["))?;
+            primitive_link(f, PrimitiveType::Slice, "[")?;
             fmt::Display::fmt(t, f)?;
-            primitive_link(f, PrimitiveType::Slice, &format!("]"))
+            primitive_link(f, PrimitiveType::Slice, "]")
         }
         clean::Vector(ref t) => write!(f, "[{:?}]", t),
         clean::FixedVector(ref t, ref s) if is_not_debug => {
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index 6b1267d89b6..528d903b8b0 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -2412,7 +2412,7 @@ mod tests {
 
         let tmpdir = tmpdir();
         let unicode = tmpdir.path();
-        let unicode = unicode.join(&format!("test-각丁ー再见"));
+        let unicode = unicode.join("test-각丁ー再见");
         check!(fs::create_dir(&unicode));
         assert!(unicode.exists());
         assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists());
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 82492d97627..0980b73e80c 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -511,8 +511,7 @@ pub fn find_export_name_attr(diag: &Handler, attrs: &[Attribute]) -> Option Parser<'a> {
                 label_sp
             };
             if self.span.contains(sp) {
-                err.span_label(self.span, &label_exp);
+                err.span_label(self.span, label_exp);
             } else {
-                err.span_label(sp, &label_exp);
-                err.span_label(self.span, &"unexpected token");
+                err.span_label(sp, label_exp);
+                err.span_label(self.span, "unexpected token");
             }
             Err(err)
         }
@@ -1512,10 +1512,10 @@ impl<'a> Parser<'a> {
                 err.span_suggestion(sum_span, "try adding parentheses:", sum_with_parens);
             }
             TyKind::Ptr(..) | TyKind::BareFn(..) => {
-                err.span_label(sum_span, &"perhaps you forgot parentheses?");
+                err.span_label(sum_span, "perhaps you forgot parentheses?");
             }
             _ => {
-                err.span_label(sum_span, &"expected a path");
+                err.span_label(sum_span, "expected a path");
             },
         }
         err.emit();
@@ -2556,7 +2556,7 @@ impl<'a> Parser<'a> {
                     let fstr = n.as_str();
                     let mut err = self.diagnostic().struct_span_err(self.prev_span,
                         &format!("unexpected token: `{}`", n));
-                    err.span_label(self.prev_span, &"unexpected token");
+                    err.span_label(self.prev_span, "unexpected token");
                     if fstr.chars().all(|x| "0123456789.".contains(x)) {
                         let float = match fstr.parse::().ok() {
                             Some(f) => f,
@@ -2708,7 +2708,7 @@ impl<'a> Parser<'a> {
                 let span_of_tilde = lo;
                 let mut err = self.diagnostic().struct_span_err(span_of_tilde,
                         "`~` can not be used as a unary operator");
-                err.span_label(span_of_tilde, &"did you mean `!`?");
+                err.span_label(span_of_tilde, "did you mean `!`?");
                 err.help("use `!` instead of `~` if you meant to perform bitwise negation");
                 err.emit();
                 (span, self.mk_unary(UnOp::Not, e))
@@ -4792,7 +4792,7 @@ impl<'a> Parser<'a> {
             sp,
             &format!("missing `fn`, `type`, or `const` for {}-item declaration",
                      item_type));
-        err.span_label(sp, &"missing `fn`, `type`, or `const`");
+        err.span_label(sp, "missing `fn`, `type`, or `const`");
         err
     }
 
-- 
cgit 1.4.1-3-g733a5


From 0e8e45c74068b72301f9045f0efc38ba8b51e0a4 Mon Sep 17 00:00:00 2001
From: Masaki Hara 
Date: Mon, 8 May 2017 22:29:24 +0900
Subject: Allow bare CR in ////-style comment.

---
 src/libsyntax/parse/lexer/mod.rs                       |  2 +-
 .../lex-bare-cr-string-literal-doc-comment.rs          |  6 ++++++
 src/test/run-pass/lex-bare-cr-nondoc-comment.rs        | 18 ++++++++++++++++++
 3 files changed, 25 insertions(+), 1 deletion(-)
 create mode 100644 src/test/run-pass/lex-bare-cr-nondoc-comment.rs

(limited to 'src/libsyntax/parse')

diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 7d2a1b3c4a4..ded1f0b599a 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -504,7 +504,7 @@ impl<'a> StringReader<'a> {
                     self.bump();
 
                     // line comments starting with "///" or "//!" are doc-comments
-                    let doc_comment = self.ch_is('/') || self.ch_is('!');
+                    let doc_comment = (self.ch_is('/') && !self.nextch_is('/')) || self.ch_is('!');
                     let start_bpos = self.pos - BytePos(2);
 
                     while !self.is_eof() {
diff --git a/src/test/parse-fail/lex-bare-cr-string-literal-doc-comment.rs b/src/test/parse-fail/lex-bare-cr-string-literal-doc-comment.rs
index f8943057543..ac085d47511 100644
--- a/src/test/parse-fail/lex-bare-cr-string-literal-doc-comment.rs
+++ b/src/test/parse-fail/lex-bare-cr-string-literal-doc-comment.rs
@@ -21,6 +21,12 @@ pub fn bar() {}
 //~^^ ERROR: bare CR not allowed in block doc-comment
 
 fn main() {
+    //! doc comment with bare CR: '
'
+    //~^ ERROR: bare CR not allowed in doc-comment
+
+    /*! block doc comment with bare CR: '
' */
+    //~^ ERROR: bare CR not allowed in block doc-comment
+
     // the following string literal has a bare CR in it
     let _s = "foo
bar"; //~ ERROR: bare CR not allowed in string
 
diff --git a/src/test/run-pass/lex-bare-cr-nondoc-comment.rs b/src/test/run-pass/lex-bare-cr-nondoc-comment.rs
new file mode 100644
index 00000000000..ba949ca8881
--- /dev/null
+++ b/src/test/run-pass/lex-bare-cr-nondoc-comment.rs
@@ -0,0 +1,18 @@
+// Copyright 2014 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.
+
+// ignore-tidy-cr
+
+// nondoc comment with bare CR: '
'
+//// nondoc comment with bare CR: '
'
+/* block nondoc comment with bare CR: '
' */
+
+fn main() {
+}
-- 
cgit 1.4.1-3-g733a5


From 7b535e1096b8a1f0d076d4b6f6aac623adb7d23f Mon Sep 17 00:00:00 2001
From: Masaki Hara 
Date: Fri, 12 May 2017 22:00:06 +0900
Subject: Disallow ._ in float literal.

---
 src/libsyntax/parse/lexer/mod.rs                     |  4 +---
 src/test/parse-fail/underscore-suffix-for-float.rs   | 13 +++++++++++++
 src/test/run-pass/underscore-method-after-integer.rs | 19 +++++++++++++++++++
 3 files changed, 33 insertions(+), 3 deletions(-)
 create mode 100644 src/test/parse-fail/underscore-suffix-for-float.rs
 create mode 100644 src/test/run-pass/underscore-method-after-integer.rs

(limited to 'src/libsyntax/parse')

diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index ded1f0b599a..a83b19c7334 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -754,9 +754,7 @@ impl<'a> StringReader<'a> {
         // integer literal followed by field/method access or a range pattern
         // (`0..2` and `12.foo()`)
         if self.ch_is('.') && !self.nextch_is('.') &&
-           !self.nextch()
-                .unwrap_or('\0')
-                .is_xid_start() {
+           !ident_start(self.nextch()) {
             // might have stuff after the ., and if it does, it needs to start
             // with a number
             self.bump();
diff --git a/src/test/parse-fail/underscore-suffix-for-float.rs b/src/test/parse-fail/underscore-suffix-for-float.rs
new file mode 100644
index 00000000000..df7d9aa374d
--- /dev/null
+++ b/src/test/parse-fail/underscore-suffix-for-float.rs
@@ -0,0 +1,13 @@
+// Copyright 2017 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.
+
+fn main() {
+    let a = 42._; //~ ERROR unexpected token: `_`
+}
diff --git a/src/test/run-pass/underscore-method-after-integer.rs b/src/test/run-pass/underscore-method-after-integer.rs
new file mode 100644
index 00000000000..af912564211
--- /dev/null
+++ b/src/test/run-pass/underscore-method-after-integer.rs
@@ -0,0 +1,19 @@
+// Copyright 2017 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.
+
+trait Tr : Sized {
+    fn _method_on_numbers(self) {}
+}
+
+impl Tr for i32 {}
+
+fn main() {
+    42._method_on_numbers();
+}
-- 
cgit 1.4.1-3-g733a5


From a9c163ebe9deeaf74699fc8642d919cdb2b5e617 Mon Sep 17 00:00:00 2001
From: Andre Bogus 
Date: Fri, 12 May 2017 20:05:39 +0200
Subject: Fix some clippy warnings in libsyntax

This is mostly removing stray ampersands, needless returns and lifetimes.
---
 src/libsyntax/ast.rs                  |  18 +--
 src/libsyntax/attr.rs                 |  17 +-
 src/libsyntax/codemap.rs              |   4 +-
 src/libsyntax/config.rs               |   8 +-
 src/libsyntax/diagnostics/plugin.rs   |   6 +-
 src/libsyntax/ext/base.rs             |  10 +-
 src/libsyntax/ext/expand.rs           |  26 ++-
 src/libsyntax/ext/quote.rs            |   4 +-
 src/libsyntax/ext/source_util.rs      |   4 +-
 src/libsyntax/ext/tt/macro_parser.rs  |  49 +++---
 src/libsyntax/ext/tt/macro_rules.rs   |  45 +++---
 src/libsyntax/ext/tt/quoted.rs        |  19 ++-
 src/libsyntax/ext/tt/transcribe.rs    |   6 +-
 src/libsyntax/feature_gate.rs         |  47 +++---
 src/libsyntax/json.rs                 |   2 +-
 src/libsyntax/parse/attr.rs           |   4 +-
 src/libsyntax/parse/classify.rs       |   4 +-
 src/libsyntax/parse/common.rs         |   2 +-
 src/libsyntax/parse/lexer/comments.rs |   2 +-
 src/libsyntax/parse/lexer/mod.rs      | 122 +++++++-------
 src/libsyntax/parse/mod.rs            | 146 ++++++++---------
 src/libsyntax/parse/obsolete.rs       |   2 +-
 src/libsyntax/parse/parser.rs         |  73 ++++-----
 src/libsyntax/parse/token.rs          |  46 +++---
 src/libsyntax/print/pp.rs             |  12 +-
 src/libsyntax/print/pprust.rs         | 297 ++++++++++++++++------------------
 src/libsyntax/std_inject.rs           |   4 +-
 src/libsyntax/test.rs                 |  19 +--
 src/libsyntax/tokenstream.rs          |  14 +-
 src/libsyntax/util/lev_distance.rs    |   7 +-
 src/libsyntax/util/move_map.rs        |   8 +-
 src/libsyntax/visit.rs                |   8 +-
 32 files changed, 498 insertions(+), 537 deletions(-)

(limited to 'src/libsyntax/parse')

diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index e5bb02fe082..24ce99208ed 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -715,7 +715,7 @@ impl Stmt {
             StmtKind::Mac(mac) => StmtKind::Mac(mac.map(|(mac, _style, attrs)| {
                 (mac, MacStmtStyle::Semicolon, attrs)
             })),
-            node @ _ => node,
+            node => node,
         };
         self
     }
@@ -1076,16 +1076,16 @@ impl LitKind {
     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::Str(..) |
+            LitKind::ByteStr(..) |
+            LitKind::Byte(..) |
+            LitKind::Char(..) |
+            LitKind::Int(_, LitIntType::Unsuffixed) |
+            LitKind::FloatUnsuffixed(..) |
             LitKind::Bool(..) => true,
             // suffixed variants
-            LitKind::Int(_, LitIntType::Signed(..)) => false,
-            LitKind::Int(_, LitIntType::Unsigned(..)) => false,
+            LitKind::Int(_, LitIntType::Signed(..)) |
+            LitKind::Int(_, LitIntType::Unsigned(..)) |
             LitKind::Float(..) => false,
         }
     }
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 0980b73e80c..45f891d8dc5 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -112,7 +112,7 @@ impl NestedMetaItem {
     /// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem.
     pub fn meta_item(&self) -> Option<&MetaItem> {
         match self.node {
-            NestedMetaItemKind::MetaItem(ref item) => Some(&item),
+            NestedMetaItemKind::MetaItem(ref item) => Some(item),
             _ => None
         }
     }
@@ -120,7 +120,7 @@ impl NestedMetaItem {
     /// Returns the Lit if self is a NestedMetaItemKind::Literal.
     pub fn literal(&self) -> Option<&Lit> {
         match self.node {
-            NestedMetaItemKind::Literal(ref lit) => Some(&lit),
+            NestedMetaItemKind::Literal(ref lit) => Some(lit),
             _ => None
         }
     }
@@ -259,7 +259,7 @@ impl MetaItem {
         match self.node {
             MetaItemKind::NameValue(ref v) => {
                 match v.node {
-                    LitKind::Str(ref s, _) => Some((*s).clone()),
+                    LitKind::Str(ref s, _) => Some(*s),
                     _ => None,
                 }
             },
@@ -1217,9 +1217,10 @@ impl LitKind {
                 Token::Literal(token::Lit::Float(symbol), Some(Symbol::intern(ty.ty_to_string())))
             }
             LitKind::FloatUnsuffixed(symbol) => Token::Literal(token::Lit::Float(symbol), None),
-            LitKind::Bool(value) => Token::Ident(Ident::with_empty_ctxt(Symbol::intern(match value {
-                true => "true",
-                false => "false",
+            LitKind::Bool(value) => Token::Ident(Ident::with_empty_ctxt(Symbol::intern(if value {
+                "true"
+            } else {
+                "false"
             }))),
         }
     }
@@ -1261,7 +1262,7 @@ impl HasAttrs for Spanned {
 
 impl HasAttrs for Vec {
     fn attrs(&self) -> &[Attribute] {
-        &self
+        self
     }
     fn map_attrs) -> Vec>(self, f: F) -> Self {
         f(self)
@@ -1270,7 +1271,7 @@ impl HasAttrs for Vec {
 
 impl HasAttrs for ThinVec {
     fn attrs(&self) -> &[Attribute] {
-        &self
+        self
     }
     fn map_attrs) -> Vec>(self, f: F) -> Self {
         f(self.into()).into()
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index 0c8be1d4f24..d32c3ec5f46 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -485,7 +485,7 @@ impl CodeMap {
         match self.span_to_snippet(sp) {
             Ok(snippet) => {
                 let snippet = snippet.split(c).nth(0).unwrap_or("").trim_right();
-                if snippet.len() > 0 && !snippet.contains('\n') {
+                if !snippet.is_empty() && !snippet.contains('\n') {
                     Span { hi: BytePos(sp.lo.0 + snippet.len() as u32), ..sp }
                 } else {
                     sp
@@ -502,7 +502,7 @@ impl CodeMap {
     pub fn get_filemap(&self, filename: &str) -> Option> {
         for fm in self.files.borrow().iter() {
             if filename == fm.name {
-               (self.dep_tracking_callback.borrow())(&fm);
+               (self.dep_tracking_callback.borrow())(fm);
                 return Some(fm.clone());
             }
         }
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index ede8a33df65..2e98c7d9626 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -123,7 +123,7 @@ impl<'a> StripUnconfigured<'a> {
                 return false;
             }
 
-            let mis = if !is_cfg(&attr) {
+            let mis = if !is_cfg(attr) {
                 return true;
             } else if let Some(mis) = attr.meta_item_list() {
                 mis
@@ -150,7 +150,7 @@ impl<'a> StripUnconfigured<'a> {
         // flag the offending attributes
         for attr in attrs.iter() {
             if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) {
-                let mut err = feature_err(&self.sess,
+                let mut err = feature_err(self.sess,
                                           "stmt_expr_attributes",
                                           attr.span,
                                           GateIssue::Language,
@@ -258,7 +258,7 @@ impl<'a> StripUnconfigured<'a> {
     pub fn configure_struct_expr_field(&mut self, field: ast::Field) -> Option {
         if !self.features.map(|features| features.struct_field_attributes).unwrap_or(true) {
             if !field.attrs.is_empty() {
-                let mut err = feature_err(&self.sess,
+                let mut err = feature_err(self.sess,
                                           "struct_field_attributes",
                                           field.span,
                                           GateIssue::Language,
@@ -290,7 +290,7 @@ impl<'a> StripUnconfigured<'a> {
         for attr in attrs.iter() {
             if !self.features.map(|features| features.struct_field_attributes).unwrap_or(true) {
                 let mut err = feature_err(
-                    &self.sess,
+                    self.sess,
                     "struct_field_attributes",
                     attr.span,
                     GateIssue::Language,
diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs
index fe5cb87ad59..ca89a80fdee 100644
--- a/src/libsyntax/diagnostics/plugin.rs
+++ b/src/libsyntax/diagnostics/plugin.rs
@@ -111,7 +111,7 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt,
     // overflow the maximum line width.
     description.map(|raw_msg| {
         let msg = raw_msg.as_str();
-        if !msg.starts_with("\n") || !msg.ends_with("\n") {
+        if !msg.starts_with('\n') || !msg.ends_with('\n') {
             ecx.span_err(span, &format!(
                 "description for error code {} doesn't start and end with a newline",
                 code
@@ -177,7 +177,7 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt,
             if let Err(e) = output_metadata(ecx,
                                             &target_triple,
                                             &crate_name.name.as_str(),
-                                            &diagnostics) {
+                                            diagnostics) {
                 ecx.span_bug(span, &format!(
                     "error writing metadata for triple `{}` and crate `{}`, error: {}, \
                      cause: {:?}",
@@ -227,7 +227,7 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt,
 
     MacEager::items(SmallVector::many(vec![
         P(ast::Item {
-            ident: name.clone(),
+            ident: *name,
             attrs: Vec::new(),
             id: ast::DUMMY_NODE_ID,
             node: ast::ItemKind::Const(
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index f731c5abdd6..f78089aaa75 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -636,7 +636,7 @@ pub struct ExpansionData {
 
 /// One of these is made during expansion and incrementally updated as we go;
 /// when a macro expansion occurs, the resulting nodes have the backtrace()
-/// -> expn_info of their expansion context stored into their span.
+/// -> `expn_info` of their expansion context stored into their span.
 pub struct ExtCtxt<'a> {
     pub parse_sess: &'a parse::ParseSess,
     pub ecfg: expand::ExpansionConfig<'a>,
@@ -709,7 +709,7 @@ impl<'a> ExtCtxt<'a> {
                 }
                 ctxt = info.call_site.ctxt;
                 last_macro = Some(info.call_site);
-                return Some(());
+                Some(())
             }).is_none() {
                 break
             }
@@ -770,9 +770,9 @@ impl<'a> ExtCtxt<'a> {
     }
     pub fn trace_macros_diag(&self) {
         for (sp, notes) in self.expansions.iter() {
-            let mut db = self.parse_sess.span_diagnostic.span_note_diag(*sp, &"trace_macro");
+            let mut db = self.parse_sess.span_diagnostic.span_note_diag(*sp, "trace_macro");
             for note in notes {
-                db.note(¬e);
+                db.note(note);
             }
             db.emit();
         }
@@ -795,7 +795,7 @@ impl<'a> ExtCtxt<'a> {
             v.push(self.ident_of(s));
         }
         v.extend(components.iter().map(|s| self.ident_of(s)));
-        return v
+        v
     }
     pub fn name_of(&self, st: &str) -> ast::Name {
         Symbol::intern(st)
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index a8aa103f80a..a5633679539 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -415,19 +415,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
 
         match *ext {
             MultiModifier(ref mac) => {
-                let meta = panictry!(attr.parse_meta(&self.cx.parse_sess));
+                let meta = panictry!(attr.parse_meta(self.cx.parse_sess));
                 let item = mac.expand(self.cx, attr.span, &meta, item);
                 kind.expect_from_annotatables(item)
             }
             MultiDecorator(ref mac) => {
                 let mut items = Vec::new();
-                let meta = panictry!(attr.parse_meta(&self.cx.parse_sess));
+                let meta = panictry!(attr.parse_meta(self.cx.parse_sess));
                 mac.expand(self.cx, attr.span, &meta, &item, &mut |item| items.push(item));
                 items.push(item);
                 kind.expect_from_annotatables(items)
             }
             SyntaxExtension::AttrProcMacro(ref mac) => {
-                let item_toks = stream_for_item(&item, &self.cx.parse_sess);
+                let item_toks = stream_for_item(&item, self.cx.parse_sess);
 
                 let span = Span { ctxt: self.cx.backtrace(), ..attr.span };
                 let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_toks);
@@ -439,7 +439,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             }
             _ => {
                 let msg = &format!("macro `{}` may not be used in attributes", attr.path);
-                self.cx.span_err(attr.span, &msg);
+                self.cx.span_err(attr.span, msg);
                 kind.dummy(attr.span)
             }
         }
@@ -454,7 +454,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         };
         let path = &mac.node.path;
 
-        let ident = ident.unwrap_or(keywords::Invalid.ident());
+        let ident = ident.unwrap_or_else(|| keywords::Invalid.ident());
         let marked_tts = noop_fold_tts(mac.node.stream(), &mut Marker(mark));
         let opt_expanded = match *ext {
             NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
@@ -591,7 +591,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             }
             _ => {
                 let msg = &format!("macro `{}` may not be used for derive attributes", attr.path);
-                self.cx.span_err(span, &msg);
+                self.cx.span_err(span, msg);
                 kind.dummy(span)
             }
         }
@@ -749,19 +749,15 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
     fn check_attributes(&mut self, attrs: &[ast::Attribute]) {
         let features = self.cx.ecfg.features.unwrap();
         for attr in attrs.iter() {
-            feature_gate::check_attribute(&attr, &self.cx.parse_sess, features);
+            feature_gate::check_attribute(attr, self.cx.parse_sess, features);
         }
     }
 }
 
 pub fn find_attr_invoc(attrs: &mut Vec) -> Option {
-    for i in 0 .. attrs.len() {
-        if !attr::is_known(&attrs[i]) && !is_builtin_attr(&attrs[i]) {
-             return Some(attrs.remove(i));
-        }
-    }
-
-    None
+    attrs.iter()
+         .position(|a| !attr::is_known(a) && !is_builtin_attr(a))
+         .map(|i| attrs.remove(i))
 }
 
 // These are pretty nasty. Ideally, we would keep the tokens around, linked from
@@ -923,7 +919,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
                 let result = noop_fold_item(item, self);
                 self.cx.current_expansion.module = orig_module;
                 self.cx.current_expansion.directory_ownership = orig_directory_ownership;
-                return result;
+                result
             }
             // Ensure that test functions are accessible from the test harness.
             ast::ItemKind::Fn(..) if self.cx.ecfg.should_test => {
diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs
index d7a85baa3ff..85ae65e6b79 100644
--- a/src/libsyntax/ext/quote.rs
+++ b/src/libsyntax/ext/quote.rs
@@ -23,7 +23,7 @@ use tokenstream::{TokenStream, TokenTree};
 ///
 /// This is registered as a set of expression syntax extension called quote!
 /// that lifts its argument token-tree to an AST representing the
-/// construction of the same token tree, with token::SubstNt interpreted
+/// construction of the same token tree, with `token::SubstNt` interpreted
 /// as antiquotes (splices).
 
 pub mod rt {
@@ -389,7 +389,7 @@ pub fn unflatten(tts: Vec) -> Vec {
                 result = results.pop().unwrap();
                 result.push(tree);
             }
-            tree @ _ => result.push(tree),
+            tree => result.push(tree),
         }
     }
     result
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index 22a5776315a..4183583d66f 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -150,7 +150,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenT
             cx.span_err(sp,
                         &format!("{} wasn't a utf-8 file",
                                 file.display()));
-            return DummyResult::expr(sp);
+            DummyResult::expr(sp)
         }
     }
 }
@@ -167,7 +167,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::Toke
         Err(e) => {
             cx.span_err(sp,
                         &format!("couldn't read {}: {}", file.display(), e));
-            return DummyResult::expr(sp);
+            DummyResult::expr(sp)
         }
         Ok(..) => {
             // Add this input file to the code map to make it available as
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index eb0b7c29f8d..8e28135b11d 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -39,40 +39,40 @@
 //! Example: Start parsing `a a a a b` against [· a $( a )* a b].
 //!
 //! Remaining input: `a a a a b`
-//! next_eis: [· a $( a )* a b]
+//! `next_eis`: `[· a $( a )* a b]`
 //!
 //! - - - Advance over an `a`. - - -
 //!
 //! Remaining input: `a a a b`
-//! cur: [a · $( a )* a b]
+//! cur: `[a · $( a )* a b]`
 //! Descend/Skip (first item).
-//! next: [a $( · a )* a b]  [a $( a )* · a b].
+//! next: `[a $( · a )* a b]  [a $( a )* · a b]`.
 //!
 //! - - - Advance over an `a`. - - -
 //!
 //! Remaining input: `a a b`
-//! cur: [a $( a · )* a b]  next: [a $( a )* a · b]
+//! cur: `[a $( a · )* a b]`  next: `[a $( a )* a · b]`
 //! Finish/Repeat (first item)
-//! next: [a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]
+//! next: `[a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]`
 //!
 //! - - - Advance over an `a`. - - - (this looks exactly like the last step)
 //!
 //! Remaining input: `a b`
-//! cur: [a $( a · )* a b]  next: [a $( a )* a · b]
+//! cur: `[a $( a · )* a b]`  next: `[a $( a )* a · b]`
 //! Finish/Repeat (first item)
-//! next: [a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]
+//! next: `[a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]`
 //!
 //! - - - Advance over an `a`. - - - (this looks exactly like the last step)
 //!
 //! Remaining input: `b`
-//! cur: [a $( a · )* a b]  next: [a $( a )* a · b]
+//! cur: `[a $( a · )* a b]`  next: `[a $( a )* a · b]`
 //! Finish/Repeat (first item)
-//! next: [a $( a )* · a b]  [a $( · a )* a b]
+//! next: `[a $( a )* · a b]  [a $( · a )* a b]`
 //!
 //! - - - Advance over a `b`. - - -
 //!
 //! Remaining input: ``
-//! eof: [a $( a )* a b ·]
+//! eof: `[a $( a )* a b ·]`
 
 pub use self::NamedMatch::*;
 pub use self::ParseResult::*;
@@ -178,20 +178,20 @@ fn initial_matcher_pos(ms: Vec, lo: BytePos) -> Box {
     })
 }
 
-/// NamedMatch is a pattern-match result for a single token::MATCH_NONTERMINAL:
+/// `NamedMatch` is a pattern-match result for a single `token::MATCH_NONTERMINAL`:
 /// so it is associated with a single ident in a parse, and all
-/// `MatchedNonterminal`s in the NamedMatch have the same nonterminal type
-/// (expr, item, etc). Each leaf in a single NamedMatch corresponds to a
-/// single token::MATCH_NONTERMINAL in the TokenTree that produced it.
+/// `MatchedNonterminal`s in the `NamedMatch` have the same nonterminal type
+/// (expr, item, etc). Each leaf in a single `NamedMatch` corresponds to a
+/// single `token::MATCH_NONTERMINAL` in the `TokenTree` that produced it.
 ///
-/// The in-memory structure of a particular NamedMatch represents the match
+/// The in-memory structure of a particular `NamedMatch` represents the match
 /// that occurred when a particular subset of a matcher was applied to a
 /// particular token tree.
 ///
-/// The width of each MatchedSeq in the NamedMatch, and the identity of the
-/// `MatchedNonterminal`s, will depend on the token tree it was applied to:
-/// each MatchedSeq corresponds to a single TTSeq in the originating
-/// token tree. The depth of the NamedMatch structure will therefore depend
+/// The width of each `MatchedSeq` in the `NamedMatch`, and the identity of
+/// the `MatchedNonterminal`s, will depend on the token tree it was applied
+/// to: each `MatchedSeq` corresponds to a single `TTSeq` in the originating
+/// token tree. The depth of the `NamedMatch` structure will therefore depend
 /// only on the nesting depth of `ast::TTSeq`s in the originating
 /// token tree it was derived from.
 
@@ -334,7 +334,7 @@ fn inner_parse_loop(sess: &ParseSess,
                 // Check if we need a separator
                 if idx == len && ei.sep.is_some() {
                     // We have a separator, and it is the current token.
-                    if ei.sep.as_ref().map(|ref sep| token_name_eq(&token, sep)).unwrap_or(false) {
+                    if ei.sep.as_ref().map(|sep| token_name_eq(token, sep)).unwrap_or(false) {
                         ei.idx += 1;
                         next_eis.push(ei);
                     }
@@ -401,7 +401,7 @@ fn inner_parse_loop(sess: &ParseSess,
                     cur_eis.push(ei);
                 }
                 TokenTree::Token(_, ref t) => {
-                    if token_name_eq(t, &token) {
+                    if token_name_eq(t, token) {
                         ei.idx += 1;
                         next_eis.push(ei);
                     }
@@ -485,11 +485,8 @@ pub fn parse(sess: &ParseSess, tts: TokenStream, ms: &[TokenTree], directory: Op
 }
 
 fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
-    match name {
-        "tt" => {
-            return token::NtTT(p.parse_token_tree());
-        }
-        _ => {}
+    if let "tt" = name {
+        return token::NtTT(p.parse_token_tree());
     }
     // check at the beginning and the parser checks after each bump
     p.process_potential_macro_variable();
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index f959ccc989e..9e3fe30e7bf 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -94,7 +94,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
                           -> Box {
     if cx.trace_macros() {
         let sp = sp.macro_backtrace().last().map(|trace| trace.call_site).unwrap_or(sp);
-        let mut values: &mut Vec = cx.expansions.entry(sp).or_insert(vec![]);
+        let mut values: &mut Vec = cx.expansions.entry(sp).or_insert_with(Vec::new);
         values.push(format!("expands to `{}! {{ {} }}`", name, arg));
     }
 
@@ -206,7 +206,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item)
     let mut valid = true;
 
     // Extract the arguments:
-    let lhses = match **argument_map.get(&lhs_nm).unwrap() {
+    let lhses = match *argument_map[&lhs_nm] {
         MatchedSeq(ref s, _) => {
             s.iter().map(|m| {
                 if let MatchedNonterminal(ref nt) = **m {
@@ -222,7 +222,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item)
         _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
     };
 
-    let rhses = match **argument_map.get(&rhs_nm).unwrap() {
+    let rhses = match *argument_map[&rhs_nm] {
         MatchedSeq(ref s, _) => {
             s.iter().map(|m| {
                 if let MatchedNonterminal(ref nt) = **m {
@@ -260,13 +260,12 @@ fn check_lhs_nt_follows(sess: &ParseSess,
                         lhs: "ed::TokenTree) -> bool {
     // lhs is going to be like TokenTree::Delimited(...), where the
     // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
-    match lhs {
-        "ed::TokenTree::Delimited(_, ref tts) => check_matcher(sess, features, &tts.tts),
-        _ => {
-            let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
-            sess.span_diagnostic.span_err(lhs.span(), msg);
-            false
-        }
+    if let quoted::TokenTree::Delimited(_, ref tts) = *lhs {
+        check_matcher(sess, features, &tts.tts)
+    } else {
+        let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
+        sess.span_diagnostic.span_err(lhs.span(), msg);
+        false
     }
     // we don't abort on errors on rejection, the driver will do that for us
     // after parsing/expansion. we can report every error in every macro this way.
@@ -283,17 +282,15 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool {
                 return false;
             },
             TokenTree::Sequence(span, ref seq) => {
-                if seq.separator.is_none() {
-                    if seq.tts.iter().all(|seq_tt| {
-                        match *seq_tt {
-                            TokenTree::Sequence(_, ref sub_seq) =>
-                                sub_seq.op == quoted::KleeneOp::ZeroOrMore,
-                            _ => false,
-                        }
-                    }) {
-                        sess.span_diagnostic.span_err(span, "repetition matches empty token tree");
-                        return false;
+                if seq.separator.is_none() && seq.tts.iter().all(|seq_tt| {
+                    match *seq_tt {
+                        TokenTree::Sequence(_, ref sub_seq) =>
+                            sub_seq.op == quoted::KleeneOp::ZeroOrMore,
+                        _ => false,
                     }
+                }) {
+                    sess.span_diagnostic.span_err(span, "repetition matches empty token tree");
+                    return false;
                 }
                 if !check_lhs_no_empty_seq(sess, &seq.tts) {
                     return false;
@@ -407,7 +404,7 @@ impl FirstSets {
                 }
             }
 
-            return first;
+            first
         }
     }
 
@@ -469,7 +466,7 @@ impl FirstSets {
         // we only exit the loop if `tts` was empty or if every
         // element of `tts` matches the empty sequence.
         assert!(first.maybe_empty);
-        return first;
+        first
     }
 }
 
@@ -579,7 +576,7 @@ fn check_matcher_core(sess: &ParseSess,
         let build_suffix_first = || {
             let mut s = first_sets.first(suffix);
             if s.maybe_empty { s.add_all(follow); }
-            return s;
+            s
         };
 
         // (we build `suffix_first` on demand below; you can tell
@@ -861,6 +858,6 @@ fn quoted_tt_to_string(tt: "ed::TokenTree) -> String {
     match *tt {
         quoted::TokenTree::Token(_, ref tok) => ::print::pprust::token_to_string(tok),
         quoted::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind),
-        _ => panic!("unexpected quoted::TokenTree::{Sequence or Delimited} in follow set checker"),
+        _ => panic!("unexpected quoted::TokenTree::{{Sequence or Delimited}} in follow set checker"),
     }
 }
diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs
index d216effbd45..fa65e9501c2 100644
--- a/src/libsyntax/ext/tt/quoted.rs
+++ b/src/libsyntax/ext/tt/quoted.rs
@@ -96,6 +96,17 @@ impl TokenTree {
         }
     }
 
+    pub fn is_empty(&self) -> bool {
+        match *self {
+            TokenTree::Delimited(_, ref delimed) => match delimed.delim {
+                token::NoDelim => delimed.tts.is_empty(),
+                _ => false,
+            },
+            TokenTree::Sequence(_, ref seq) => seq.tts.is_empty(),
+            _ => true,
+        }
+    }
+
     pub fn get_tt(&self, index: usize) -> TokenTree {
         match (self, index) {
             (&TokenTree::Delimited(_, ref delimed), _) if delimed.delim == token::NoDelim => {
@@ -144,9 +155,9 @@ pub fn parse(input: tokenstream::TokenStream, expect_matchers: bool, sess: &Pars
                             }
                             _ => end_sp,
                         },
-                        tree @ _ => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span),
+                        tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span),
                     },
-                    tree @ _ => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp),
+                    tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp),
                 };
                 sess.missing_fragment_specifiers.borrow_mut().insert(span);
                 result.push(TokenTree::MetaVarDecl(span, ident, keywords::Invalid.ident()));
@@ -228,10 +239,10 @@ fn parse_sep_and_kleene_op(input: &mut I, span: Span, sess: &ParseSess)
                     Some(op) => return (Some(tok), op),
                     None => span,
                 },
-                tree @ _ => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span),
+                tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span),
             }
         },
-        tree @ _ => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span),
+        tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span),
     };
 
     sess.span_diagnostic.span_err(span, "expected `*` or `+`");
diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs
index 947089b0b9a..2a435bdea10 100644
--- a/src/libsyntax/ext/tt/transcribe.rs
+++ b/src/libsyntax/ext/tt/transcribe.rs
@@ -121,20 +121,20 @@ pub fn transcribe(sp_diag: &Handler,
                                          &repeats) {
                     LockstepIterSize::Unconstrained => {
                         panic!(sp_diag.span_fatal(
-                            sp.clone(), /* blame macro writer */
+                            sp, /* blame macro writer */
                             "attempted to repeat an expression \
                              containing no syntax \
                              variables matched as repeating at this depth"));
                     }
                     LockstepIterSize::Contradiction(ref msg) => {
                         // FIXME #2887 blame macro invoker instead
-                        panic!(sp_diag.span_fatal(sp.clone(), &msg[..]));
+                        panic!(sp_diag.span_fatal(sp, &msg[..]));
                     }
                     LockstepIterSize::Constraint(len, _) => {
                         if len == 0 {
                             if seq.op == quoted::KleeneOp::OneOrMore {
                                 // FIXME #2887 blame invoker
-                                panic!(sp_diag.span_fatal(sp.clone(),
+                                panic!(sp_diag.span_fatal(sp,
                                                           "this must repeat at least once"));
                             }
                         } else {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index b6a2c983fd4..f95693f6820 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -472,7 +472,7 @@ pub enum Stability {
 impl ::std::fmt::Debug for AttributeGate {
     fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
         match *self {
-            Gated(ref stab, ref name, ref expl, _) =>
+            Gated(ref stab, name, expl, _) =>
                 write!(fmt, "Gated({:?}, {}, {})", stab, name, expl),
             Ungated => write!(fmt, "Ungated")
         }
@@ -816,7 +816,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
 ];
 
 // cfg(...)'s that are feature gated
-const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
+const GATED_CFGS: &[(&str, &str, fn(&Features) -> bool)] = &[
     // (name in cfg, feature, function to check if the feature is enabled)
     ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)),
     ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
@@ -881,7 +881,7 @@ impl<'a> Context<'a> {
         let name = unwrap_or!(attr.name(), return).as_str();
         for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES {
             if name == n {
-                if let &Gated(_, ref name, ref desc, ref has_feature) = gateage {
+                if let Gated(_, name, desc, ref has_feature) = *gateage {
                     gate_feature_fn!(self, has_feature, attr.span, name, desc);
                 }
                 debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage);
@@ -1098,7 +1098,7 @@ fn contains_novel_literal(item: &ast::MetaItem) -> bool {
         NameValue(ref lit) => !lit.node.is_str(),
         List(ref list) => list.iter().any(|li| {
             match li.node {
-                MetaItem(ref mi) => contains_novel_literal(&mi),
+                MetaItem(ref mi) => contains_novel_literal(mi),
                 Literal(_) => true,
             }
         }),
@@ -1120,7 +1120,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             return
         }
 
-        let meta = panictry!(attr.parse_meta(&self.context.parse_sess));
+        let meta = panictry!(attr.parse_meta(self.context.parse_sess));
         if contains_novel_literal(&meta) {
             gate_feature_post!(&self, attr_literals, attr.span,
                                "non-string literals in attributes, or string \
@@ -1216,14 +1216,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             }
 
             ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => {
-                match polarity {
-                    ast::ImplPolarity::Negative => {
-                        gate_feature_post!(&self, optin_builtin_traits,
-                                           i.span,
-                                           "negative trait bounds are not yet fully implemented; \
-                                            use marker types for now");
-                    },
-                    _ => {}
+                if let ast::ImplPolarity::Negative = polarity {
+                    gate_feature_post!(&self, optin_builtin_traits,
+                                       i.span,
+                                       "negative trait bounds are not yet fully implemented; \
+                                        use marker types for now");
                 }
 
                 if let ast::Defaultness::Default = defaultness {
@@ -1272,10 +1269,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
 
     fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
         if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
-            match output_ty.node {
-                ast::TyKind::Never => return,
-                _ => (),
-            };
+            if let ast::TyKind::Never = output_ty.node {
+                return
+            }
             self.visit_ty(output_ty)
         }
     }
@@ -1373,17 +1369,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 span: Span,
                 _node_id: NodeId) {
         // check for const fn declarations
-        match fn_kind {
-            FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) => {
-                gate_feature_post!(&self, const_fn, span, "const fn is unstable");
-            }
-            _ => {
-                // stability of const fn methods are covered in
-                // visit_trait_item and visit_impl_item below; this is
-                // because default methods don't pass through this
-                // point.
-            }
+        if let FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) =
+            fn_kind {
+            gate_feature_post!(&self, const_fn, span, "const fn is unstable");
         }
+        // stability of const fn methods are covered in
+        // visit_trait_item and visit_impl_item below; this is
+        // because default methods don't pass through this
+        // point.
 
         match fn_kind {
             FnKind::ItemFn(_, _, _, _, abi, _, _) |
diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs
index 0271ddbccbf..ccc2a2aef31 100644
--- a/src/libsyntax/json.rs
+++ b/src/libsyntax/json.rs
@@ -330,7 +330,7 @@ impl DiagnosticSpanLine {
                       })
                      .collect()
              })
-            .unwrap_or(vec![])
+            .unwrap_or_else(|_| vec![])
     }
 }
 
diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs
index 92cec462ffb..082930777e5 100644
--- a/src/libsyntax/parse/attr.rs
+++ b/src/libsyntax/parse/attr.rs
@@ -62,7 +62,7 @@ impl<'a> Parser<'a> {
                 _ => break,
             }
         }
-        return Ok(attrs);
+        Ok(attrs)
     }
 
     /// Matches `attribute = # ! [ meta_item ]`
@@ -182,7 +182,7 @@ impl<'a> Parser<'a> {
                     }
 
                     let attr = self.parse_attribute(true)?;
-                    assert!(attr.style == ast::AttrStyle::Inner);
+                    assert_eq!(attr.style, ast::AttrStyle::Inner);
                     attrs.push(attr);
                 }
                 token::DocComment(s) => {
diff --git a/src/libsyntax/parse/classify.rs b/src/libsyntax/parse/classify.rs
index 4fe4ec7e4c0..c2755cf0591 100644
--- a/src/libsyntax/parse/classify.rs
+++ b/src/libsyntax/parse/classify.rs
@@ -43,14 +43,14 @@ pub fn expr_is_simple_block(e: &ast::Expr) -> bool {
 }
 
 /// this statement requires a semicolon after it.
-/// note that in one case (stmt_semi), we've already
+/// note that in one case (`stmt_semi`), we've already
 /// seen the semicolon, and thus don't need another.
 pub fn stmt_ends_with_semi(stmt: &ast::StmtKind) -> bool {
     match *stmt {
         ast::StmtKind::Local(_) => true,
         ast::StmtKind::Item(_) => false,
         ast::StmtKind::Expr(ref e) => expr_requires_semi_to_be_stmt(e),
-        ast::StmtKind::Semi(..) => false,
+        ast::StmtKind::Semi(..) |
         ast::StmtKind::Mac(..) => false,
     }
 }
diff --git a/src/libsyntax/parse/common.rs b/src/libsyntax/parse/common.rs
index b57708f9193..fe931f7cf6a 100644
--- a/src/libsyntax/parse/common.rs
+++ b/src/libsyntax/parse/common.rs
@@ -12,7 +12,7 @@
 
 use parse::token;
 
-/// SeqSep : a sequence separator (token)
+/// `SeqSep` : a sequence separator (token)
 /// and whether a trailing separator is allowed.
 pub struct SeqSep {
     pub sep: Option,
diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs
index 7ac322b144c..8b545d3b909 100644
--- a/src/libsyntax/parse/lexer/comments.rs
+++ b/src/libsyntax/parse/lexer/comments.rs
@@ -77,7 +77,7 @@ pub fn strip_doc_comment_decoration(comment: &str) -> String {
         while j > i && lines[j - 1].trim().is_empty() {
             j -= 1;
         }
-        lines[i..j].iter().cloned().collect()
+        lines[i..j].to_vec()
     }
 
     /// remove a "[ \t]*\*" block from each line, if possible
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index ded1f0b599a..454167695e1 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -144,7 +144,7 @@ impl<'a> StringReader<'a> {
 
 impl<'a> StringReader<'a> {
     /// For comments.rs, which hackily pokes into next_pos and ch
-    pub fn new_raw<'b>(sess: &'a ParseSess, filemap: Rc) -> Self {
+    pub fn new_raw(sess: &'a ParseSess, filemap: Rc) -> Self {
         let mut sr = StringReader::new_raw_internal(sess, filemap);
         sr.bump();
         sr
@@ -180,7 +180,7 @@ impl<'a> StringReader<'a> {
 
     pub fn new(sess: &'a ParseSess, filemap: Rc) -> Self {
         let mut sr = StringReader::new_raw(sess, filemap);
-        if let Err(_) = sr.advance_token() {
+        if sr.advance_token().is_err() {
             sr.emit_fatal_errors();
             panic!(FatalError);
         }
@@ -205,7 +205,7 @@ impl<'a> StringReader<'a> {
 
         sr.bump();
 
-        if let Err(_) = sr.advance_token() {
+        if sr.advance_token().is_err() {
             sr.emit_fatal_errors();
             panic!(FatalError);
         }
@@ -525,7 +525,7 @@ impl<'a> StringReader<'a> {
                         self.bump();
                     }
 
-                    return if doc_comment {
+                    if doc_comment {
                         self.with_str_from(start_bpos, |string| {
                             // comments with only more "/"s are not doc comments
                             let tok = if is_doc_comment(string) {
@@ -544,7 +544,7 @@ impl<'a> StringReader<'a> {
                             tok: token::Comment,
                             sp: mk_sp(start_bpos, self.pos),
                         })
-                    };
+                    }
                 }
                 Some('*') => {
                     self.bump();
@@ -766,7 +766,7 @@ impl<'a> StringReader<'a> {
             }
             let pos = self.pos;
             self.check_float_base(start_bpos, pos, base);
-            return token::Float(self.name_from(start_bpos));
+            token::Float(self.name_from(start_bpos))
         } else {
             // it might be a float if it has an exponent
             if self.ch_is('e') || self.ch_is('E') {
@@ -776,7 +776,7 @@ impl<'a> StringReader<'a> {
                 return token::Float(self.name_from(start_bpos));
             }
             // but we certainly have an integer!
-            return token::Integer(self.name_from(start_bpos));
+            token::Integer(self.name_from(start_bpos))
         }
     }
 
@@ -1053,9 +1053,9 @@ impl<'a> StringReader<'a> {
         self.bump();
         if self.ch_is('=') {
             self.bump();
-            return token::BinOpEq(op);
+            token::BinOpEq(op)
         } else {
-            return token::BinOp(op);
+            token::BinOp(op)
         }
     }
 
@@ -1102,15 +1102,15 @@ impl<'a> StringReader<'a> {
             // One-byte tokens.
             ';' => {
                 self.bump();
-                return Ok(token::Semi);
+                Ok(token::Semi)
             }
             ',' => {
                 self.bump();
-                return Ok(token::Comma);
+                Ok(token::Comma)
             }
             '.' => {
                 self.bump();
-                return if self.ch_is('.') {
+                if self.ch_is('.') {
                     self.bump();
                     if self.ch_is('.') {
                         self.bump();
@@ -1120,61 +1120,61 @@ impl<'a> StringReader<'a> {
                     }
                 } else {
                     Ok(token::Dot)
-                };
+                }
             }
             '(' => {
                 self.bump();
-                return Ok(token::OpenDelim(token::Paren));
+                Ok(token::OpenDelim(token::Paren))
             }
             ')' => {
                 self.bump();
-                return Ok(token::CloseDelim(token::Paren));
+                Ok(token::CloseDelim(token::Paren))
             }
             '{' => {
                 self.bump();
-                return Ok(token::OpenDelim(token::Brace));
+                Ok(token::OpenDelim(token::Brace))
             }
             '}' => {
                 self.bump();
-                return Ok(token::CloseDelim(token::Brace));
+                Ok(token::CloseDelim(token::Brace))
             }
             '[' => {
                 self.bump();
-                return Ok(token::OpenDelim(token::Bracket));
+                Ok(token::OpenDelim(token::Bracket))
             }
             ']' => {
                 self.bump();
-                return Ok(token::CloseDelim(token::Bracket));
+                Ok(token::CloseDelim(token::Bracket))
             }
             '@' => {
                 self.bump();
-                return Ok(token::At);
+                Ok(token::At)
             }
             '#' => {
                 self.bump();
-                return Ok(token::Pound);
+                Ok(token::Pound)
             }
             '~' => {
                 self.bump();
-                return Ok(token::Tilde);
+                Ok(token::Tilde)
             }
             '?' => {
                 self.bump();
-                return Ok(token::Question);
+                Ok(token::Question)
             }
             ':' => {
                 self.bump();
                 if self.ch_is(':') {
                     self.bump();
-                    return Ok(token::ModSep);
+                    Ok(token::ModSep)
                 } else {
-                    return Ok(token::Colon);
+                    Ok(token::Colon)
                 }
             }
 
             '$' => {
                 self.bump();
-                return Ok(token::Dollar);
+                Ok(token::Dollar)
             }
 
             // Multi-byte tokens.
@@ -1182,21 +1182,21 @@ impl<'a> StringReader<'a> {
                 self.bump();
                 if self.ch_is('=') {
                     self.bump();
-                    return Ok(token::EqEq);
+                    Ok(token::EqEq)
                 } else if self.ch_is('>') {
                     self.bump();
-                    return Ok(token::FatArrow);
+                    Ok(token::FatArrow)
                 } else {
-                    return Ok(token::Eq);
+                    Ok(token::Eq)
                 }
             }
             '!' => {
                 self.bump();
                 if self.ch_is('=') {
                     self.bump();
-                    return Ok(token::Ne);
+                    Ok(token::Ne)
                 } else {
-                    return Ok(token::Not);
+                    Ok(token::Not)
                 }
             }
             '<' => {
@@ -1204,21 +1204,21 @@ impl<'a> StringReader<'a> {
                 match self.ch.unwrap_or('\x00') {
                     '=' => {
                         self.bump();
-                        return Ok(token::Le);
+                        Ok(token::Le)
                     }
                     '<' => {
-                        return Ok(self.binop(token::Shl));
+                        Ok(self.binop(token::Shl))
                     }
                     '-' => {
                         self.bump();
                         match self.ch.unwrap_or('\x00') {
                             _ => {
-                                return Ok(token::LArrow);
+                                Ok(token::LArrow)
                             }
                         }
                     }
                     _ => {
-                        return Ok(token::Lt);
+                        Ok(token::Lt)
                     }
                 }
             }
@@ -1227,13 +1227,13 @@ impl<'a> StringReader<'a> {
                 match self.ch.unwrap_or('\x00') {
                     '=' => {
                         self.bump();
-                        return Ok(token::Ge);
+                        Ok(token::Ge)
                     }
                     '>' => {
-                        return Ok(self.binop(token::Shr));
+                        Ok(self.binop(token::Shr))
                     }
                     _ => {
-                        return Ok(token::Gt);
+                        Ok(token::Gt)
                     }
                 }
             }
@@ -1303,7 +1303,7 @@ impl<'a> StringReader<'a> {
                 };
                 self.bump(); // advance ch past token
                 let suffix = self.scan_optional_raw_name();
-                return Ok(token::Literal(token::Char(id), suffix));
+                Ok(token::Literal(token::Char(id), suffix))
             }
             'b' => {
                 self.bump();
@@ -1314,7 +1314,7 @@ impl<'a> StringReader<'a> {
                     _ => unreachable!(),  // Should have been a token::Ident above.
                 };
                 let suffix = self.scan_optional_raw_name();
-                return Ok(token::Literal(lit, suffix));
+                Ok(token::Literal(lit, suffix))
             }
             '"' => {
                 let start_bpos = self.pos;
@@ -1345,7 +1345,7 @@ impl<'a> StringReader<'a> {
                 };
                 self.bump();
                 let suffix = self.scan_optional_raw_name();
-                return Ok(token::Literal(token::Str_(id), suffix));
+                Ok(token::Literal(token::Str_(id), suffix))
             }
             'r' => {
                 let start_bpos = self.pos;
@@ -1416,24 +1416,24 @@ impl<'a> StringReader<'a> {
                     Symbol::intern("??")
                 };
                 let suffix = self.scan_optional_raw_name();
-                return Ok(token::Literal(token::StrRaw(id, hash_count), suffix));
+                Ok(token::Literal(token::StrRaw(id, hash_count), suffix))
             }
             '-' => {
                 if self.nextch_is('>') {
                     self.bump();
                     self.bump();
-                    return Ok(token::RArrow);
+                    Ok(token::RArrow)
                 } else {
-                    return Ok(self.binop(token::Minus));
+                    Ok(self.binop(token::Minus))
                 }
             }
             '&' => {
                 if self.nextch_is('&') {
                     self.bump();
                     self.bump();
-                    return Ok(token::AndAnd);
+                    Ok(token::AndAnd)
                 } else {
-                    return Ok(self.binop(token::And));
+                    Ok(self.binop(token::And))
                 }
             }
             '|' => {
@@ -1441,27 +1441,27 @@ impl<'a> StringReader<'a> {
                     Some('|') => {
                         self.bump();
                         self.bump();
-                        return Ok(token::OrOr);
+                        Ok(token::OrOr)
                     }
                     _ => {
-                        return Ok(self.binop(token::Or));
+                        Ok(self.binop(token::Or))
                     }
                 }
             }
             '+' => {
-                return Ok(self.binop(token::Plus));
+                Ok(self.binop(token::Plus))
             }
             '*' => {
-                return Ok(self.binop(token::Star));
+                Ok(self.binop(token::Star))
             }
             '/' => {
-                return Ok(self.binop(token::Slash));
+                Ok(self.binop(token::Slash))
             }
             '^' => {
-                return Ok(self.binop(token::Caret));
+                Ok(self.binop(token::Caret))
             }
             '%' => {
-                return Ok(self.binop(token::Percent));
+                Ok(self.binop(token::Percent))
             }
             c => {
                 let last_bpos = self.pos;
@@ -1470,7 +1470,7 @@ impl<'a> StringReader<'a> {
                                                           bpos,
                                                           "unknown start of token",
                                                           c);
-                unicode_chars::check_for_substitution(&self, c, &mut err);
+                unicode_chars::check_for_substitution(self, c, &mut err);
                 self.fatal_errs.push(err);
                 Err(())
             }
@@ -1492,14 +1492,14 @@ impl<'a> StringReader<'a> {
         if self.ch_is('\n') {
             self.bump();
         }
-        return val;
+        val
     }
 
     fn read_one_line_comment(&mut self) -> String {
         let val = self.read_to_eol();
         assert!((val.as_bytes()[0] == b'/' && val.as_bytes()[1] == b'/') ||
                 (val.as_bytes()[0] == b'#' && val.as_bytes()[1] == b'!'));
-        return val;
+        val
     }
 
     fn consume_non_eol_whitespace(&mut self) {
@@ -1543,7 +1543,7 @@ impl<'a> StringReader<'a> {
             Symbol::intern("?")
         };
         self.bump(); // advance ch past token
-        return token::Byte(id);
+        token::Byte(id)
     }
 
     fn scan_byte_escape(&mut self, delim: char, below_0x7f_only: bool) -> bool {
@@ -1576,7 +1576,7 @@ impl<'a> StringReader<'a> {
             Symbol::intern("??")
         };
         self.bump();
-        return token::ByteStr(id);
+        token::ByteStr(id)
     }
 
     fn scan_raw_byte_string(&mut self) -> token::Lit {
@@ -1629,8 +1629,8 @@ impl<'a> StringReader<'a> {
             self.bump();
         }
         self.bump();
-        return token::ByteStrRaw(self.name_from_to(content_start_bpos, content_end_bpos),
-                                 hash_count);
+        token::ByteStrRaw(self.name_from_to(content_start_bpos, content_end_bpos),
+                                 hash_count)
     }
 }
 
@@ -1648,7 +1648,7 @@ fn in_range(c: Option, lo: char, hi: char) -> bool {
 }
 
 fn is_dec_digit(c: Option) -> bool {
-    return in_range(c, '0', '9');
+    in_range(c, '0', '9')
 }
 
 pub fn is_doc_comment(s: &str) -> bool {
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index fe3ca1cf230..4fcf7614622 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -107,18 +107,18 @@ pub fn parse_crate_attrs_from_file<'a>(input: &Path, sess: &'a ParseSess)
     parser.parse_inner_attributes()
 }
 
-pub fn parse_crate_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess)
-                                       -> PResult<'a, ast::Crate> {
+pub fn parse_crate_from_source_str(name: String, source: String, sess: &ParseSess)
+                                       -> PResult {
     new_parser_from_source_str(sess, name, source).parse_crate_mod()
 }
 
-pub fn parse_crate_attrs_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess)
-                                             -> PResult<'a, Vec> {
+pub fn parse_crate_attrs_from_source_str(name: String, source: String, sess: &ParseSess)
+                                             -> PResult> {
     new_parser_from_source_str(sess, name, source).parse_inner_attributes()
 }
 
-pub fn parse_expr_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess)
-                                      -> PResult<'a, P> {
+pub fn parse_expr_from_source_str(name: String, source: String, sess: &ParseSess)
+                                      -> PResult> {
     new_parser_from_source_str(sess, name, source).parse_expr()
 }
 
@@ -126,29 +126,29 @@ pub fn parse_expr_from_source_str<'a>(name: String, source: String, sess: &'a Pa
 ///
 /// Returns `Ok(Some(item))` when successful, `Ok(None)` when no item was found, and`Err`
 /// when a syntax error occurred.
-pub fn parse_item_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess)
-                                      -> PResult<'a, Option>> {
+pub fn parse_item_from_source_str(name: String, source: String, sess: &ParseSess)
+                                      -> PResult>> {
     new_parser_from_source_str(sess, name, source).parse_item()
 }
 
-pub fn parse_meta_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess)
-                                      -> PResult<'a, ast::MetaItem> {
+pub fn parse_meta_from_source_str(name: String, source: String, sess: &ParseSess)
+                                      -> PResult {
     new_parser_from_source_str(sess, name, source).parse_meta_item()
 }
 
-pub fn parse_stmt_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess)
-                                      -> PResult<'a, Option> {
+pub fn parse_stmt_from_source_str(name: String, source: String, sess: &ParseSess)
+                                      -> PResult> {
     new_parser_from_source_str(sess, name, source).parse_stmt()
 }
 
-pub fn parse_stream_from_source_str<'a>(name: String, source: String, sess: &'a ParseSess)
+pub fn parse_stream_from_source_str(name: String, source: String, sess: &ParseSess)
                                         -> TokenStream {
     filemap_to_stream(sess, sess.codemap().new_filemap(name, source))
 }
 
 // Create a new parser from a source string
-pub fn new_parser_from_source_str<'a>(sess: &'a ParseSess, name: String, source: String)
-                                      -> Parser<'a> {
+pub fn new_parser_from_source_str(sess: &ParseSess, name: String, source: String)
+                                      -> Parser {
     filemap_to_parser(sess, sess.codemap().new_filemap(name, source))
 }
 
@@ -173,7 +173,7 @@ pub fn new_sub_parser_from_file<'a>(sess: &'a ParseSess,
 }
 
 /// Given a filemap and config, return a parser
-pub fn filemap_to_parser<'a>(sess: &'a ParseSess, filemap: Rc, ) -> Parser<'a> {
+pub fn filemap_to_parser(sess: & ParseSess, filemap: Rc, ) -> Parser {
     let end_pos = filemap.end_pos;
     let mut parser = stream_to_parser(sess, filemap_to_stream(sess, filemap));
 
@@ -186,7 +186,7 @@ pub fn filemap_to_parser<'a>(sess: &'a ParseSess, filemap: Rc, ) -> Par
 
 // must preserve old name for now, because quote! from the *existing*
 // compiler expands into it
-pub fn new_parser_from_tts<'a>(sess: &'a ParseSess, tts: Vec) -> Parser<'a> {
+pub fn new_parser_from_tts(sess: &ParseSess, tts: Vec) -> Parser {
     stream_to_parser(sess, tts.into_iter().collect())
 }
 
@@ -216,8 +216,8 @@ pub fn filemap_to_stream(sess: &ParseSess, filemap: Rc) -> TokenStream
     panictry!(srdr.parse_all_token_trees())
 }
 
-/// Given stream and the ParseSess, produce a parser
-pub fn stream_to_parser<'a>(sess: &'a ParseSess, stream: TokenStream) -> Parser<'a> {
+/// Given stream and the `ParseSess`, produce a parser
+pub fn stream_to_parser(sess: &ParseSess, stream: TokenStream) -> Parser {
     Parser::new(sess, stream, None, false)
 }
 
@@ -251,7 +251,7 @@ pub fn char_lit(lit: &str) -> (char, isize) {
             (c, 4)
         }
         'u' => {
-            assert!(lit.as_bytes()[2] == b'{');
+            assert_eq!(lit.as_bytes()[2], b'{');
             let idx = lit.find('}').unwrap();
             let v = u32::from_str_radix(&lit[3..idx], 16).unwrap();
             let c = char::from_u32(v).unwrap();
@@ -287,51 +287,46 @@ pub fn str_lit(lit: &str) -> String {
     }
 
     let mut chars = lit.char_indices().peekable();
-    loop {
-        match chars.next() {
-            Some((i, c)) => {
-                match c {
-                    '\\' => {
-                        let ch = chars.peek().unwrap_or_else(|| {
-                            panic!("{}", error(i))
-                        }).1;
-
-                        if ch == '\n' {
-                            eat(&mut chars);
-                        } else if ch == '\r' {
-                            chars.next();
-                            let ch = chars.peek().unwrap_or_else(|| {
-                                panic!("{}", error(i))
-                            }).1;
-
-                            if ch != '\n' {
-                                panic!("lexer accepted bare CR");
-                            }
-                            eat(&mut chars);
-                        } else {
-                            // otherwise, a normal escape
-                            let (c, n) = char_lit(&lit[i..]);
-                            for _ in 0..n - 1 { // we don't need to move past the first \
-                                chars.next();
-                            }
-                            res.push(c);
-                        }
-                    },
-                    '\r' => {
-                        let ch = chars.peek().unwrap_or_else(|| {
-                            panic!("{}", error(i))
-                        }).1;
+    while let Some((i, c)) = chars.next() {
+        match c {
+            '\\' => {
+                let ch = chars.peek().unwrap_or_else(|| {
+                    panic!("{}", error(i))
+                }).1;
+
+                if ch == '\n' {
+                    eat(&mut chars);
+                } else if ch == '\r' {
+                    chars.next();
+                    let ch = chars.peek().unwrap_or_else(|| {
+                        panic!("{}", error(i))
+                    }).1;
 
-                        if ch != '\n' {
-                            panic!("lexer accepted bare CR");
-                        }
+                    if ch != '\n' {
+                        panic!("lexer accepted bare CR");
+                    }
+                    eat(&mut chars);
+                } else {
+                    // otherwise, a normal escape
+                    let (c, n) = char_lit(&lit[i..]);
+                    for _ in 0..n - 1 { // we don't need to move past the first \
                         chars.next();
-                        res.push('\n');
                     }
-                    c => res.push(c),
+                    res.push(c);
                 }
             },
-            None => break
+            '\r' => {
+                let ch = chars.peek().unwrap_or_else(|| {
+                    panic!("{}", error(i))
+                }).1;
+
+                if ch != '\n' {
+                    panic!("lexer accepted bare CR");
+                }
+                chars.next();
+                res.push('\n');
+            }
+            c => res.push(c),
         }
     }
 
@@ -348,20 +343,15 @@ pub fn raw_str_lit(lit: &str) -> String {
 
     // FIXME #8372: This could be a for-loop if it didn't borrow the iterator
     let mut chars = lit.chars().peekable();
-    loop {
-        match chars.next() {
-            Some(c) => {
-                if c == '\r' {
-                    if *chars.peek().unwrap() != '\n' {
-                        panic!("lexer accepted bare CR");
-                    }
-                    chars.next();
-                    res.push('\n');
-                } else {
-                    res.push(c);
-                }
-            },
-            None => break
+    while let Some(c) = chars.next() {
+        if c == '\r' {
+            if *chars.peek().unwrap() != '\n' {
+                panic!("lexer accepted bare CR");
+            }
+            chars.next();
+            res.push('\n');
+        } else {
+            res.push(c);
         }
     }
 
@@ -459,7 +449,7 @@ pub fn byte_lit(lit: &str) -> (u8, usize) {
     if lit.len() == 1 {
         (lit.as_bytes()[0], 1)
     } else {
-        assert!(lit.as_bytes()[0] == b'\\', err(0));
+        assert_eq!(lit.as_bytes()[0], b'\\', "{}", err(0));
         let b = match lit.as_bytes()[1] {
             b'"' => b'"',
             b'n' => b'\n',
@@ -480,7 +470,7 @@ pub fn byte_lit(lit: &str) -> (u8, usize) {
                 }
             }
         };
-        return (b, 2);
+        (b, 2)
     }
 }
 
@@ -491,7 +481,7 @@ pub fn byte_str_lit(lit: &str) -> Rc> {
     let error = |i| format!("lexer should have rejected {} at {}", lit, i);
 
     /// Eat everything up to a non-whitespace
-    fn eat<'a, I: Iterator>(it: &mut iter::Peekable) {
+    fn eat>(it: &mut iter::Peekable) {
         loop {
             match it.peek().map(|x| x.1) {
                 Some(b' ') | Some(b'\n') | Some(b'\r') | Some(b'\t') => {
@@ -578,7 +568,7 @@ pub fn integer_lit(s: &str, suffix: Option, diag: Option<(Span, &Handler
             if let Some(err) = err {
                 err!(diag, |span, diag| diag.span_err(span, err));
             }
-            return filtered_float_lit(Symbol::intern(&s), Some(suf), diag)
+            return filtered_float_lit(Symbol::intern(s), Some(suf), diag)
         }
     }
 
diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs
index d5baec675e4..078e86aa294 100644
--- a/src/libsyntax/parse/obsolete.rs
+++ b/src/libsyntax/parse/obsolete.rs
@@ -59,7 +59,7 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
 
         if !self.obsolete_set.contains(&kind) &&
             (error || self.sess.span_diagnostic.can_emit_warnings) {
-            err.note(&format!("{}", desc));
+            err.note(desc);
             self.obsolete_set.insert(kind);
         }
         err.emit();
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index ca1351e3b41..28c57e0855f 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -248,7 +248,7 @@ impl TokenCursor {
     fn next_desugared(&mut self) -> TokenAndSpan {
         let (sp, name) = match self.next() {
             TokenAndSpan { sp, tok: token::DocComment(name) } => (sp, name),
-            tok @ _ => return tok,
+            tok => return tok,
         };
 
         let stripped = strip_doc_comment_decoration(&name.as_str());
@@ -354,7 +354,7 @@ pub enum Error {
 }
 
 impl Error {
-    pub fn span_err<'a>(self, sp: Span, handler: &'a errors::Handler) -> DiagnosticBuilder<'a> {
+    pub fn span_err(self, sp: Span, handler: &errors::Handler) -> DiagnosticBuilder {
         match self {
             Error::FileNotFoundForModule { ref mod_name,
                                            ref default_path,
@@ -478,9 +478,10 @@ impl<'a> Parser<'a> {
     }
 
     fn next_tok(&mut self) -> TokenAndSpan {
-        let mut next = match self.desugar_doc_comments {
-            true => self.token_cursor.next_desugared(),
-            false => self.token_cursor.next(),
+        let mut next = if self.desugar_doc_comments {
+            self.token_cursor.next_desugared()
+        } else {
+            self.token_cursor.next()
         };
         if next.sp == syntax_pos::DUMMY_SP {
             next.sp = self.prev_span;
@@ -551,7 +552,7 @@ impl<'a> Parser<'a> {
             // This might be a sign we need a connect method on Iterator.
             let b = i.next()
                      .map_or("".to_string(), |t| t.to_string());
-            i.enumerate().fold(b, |mut b, (i, ref a)| {
+            i.enumerate().fold(b, |mut b, (i, a)| {
                 if tokens.len() > 2 && i == tokens.len() - 2 {
                     b.push_str(", or ");
                 } else if tokens.len() == 2 && i == tokens.len() - 2 {
@@ -985,18 +986,15 @@ impl<'a> Parser<'a> {
                 token::CloseDelim(..) | token::Eof => break,
                 _ => {}
             };
-            match sep.sep {
-                Some(ref t) => {
-                    if first {
-                        first = false;
-                    } else {
-                        if let Err(e) = self.expect(t) {
-                            fe(e);
-                            break;
-                        }
+            if let Some(ref t) = sep.sep {
+                if first {
+                    first = false;
+                } else {
+                    if let Err(e) = self.expect(t) {
+                        fe(e);
+                        break;
                     }
                 }
-                _ => ()
             }
             if sep.trailing_sep_allowed && kets.iter().any(|k| self.check(k)) {
                 break;
@@ -1493,7 +1491,7 @@ impl<'a> Parser<'a> {
         let sum_span = ty.span.to(self.prev_span);
 
         let mut err = struct_span_err!(self.sess.span_diagnostic, sum_span, E0178,
-            "expected a path on the left-hand side of `+`, not `{}`", pprust::ty_to_string(&ty));
+            "expected a path on the left-hand side of `+`, not `{}`", pprust::ty_to_string(ty));
 
         match ty.node {
             TyKind::Rptr(ref lifetime, ref mut_ty) => {
@@ -1547,8 +1545,8 @@ impl<'a> Parser<'a> {
 
     pub fn is_named_argument(&mut self) -> bool {
         let offset = match self.token {
-            token::BinOp(token::And) => 1,
-            token::AndAnd => 1,
+            token::BinOp(token::And) |
+            token::AndAnd |
             _ if self.token.is_keyword(keywords::Mut) => 1,
             _ => 0
         };
@@ -2571,7 +2569,7 @@ impl<'a> Parser<'a> {
                             s.print_usize(float.trunc() as usize)?;
                             s.pclose()?;
                             word(&mut s.s, ".")?;
-                            word(&mut s.s, fstr.splitn(2, ".").last().unwrap())
+                            word(&mut s.s, fstr.splitn(2, '.').last().unwrap())
                         });
                         err.span_suggestion(
                             lo.to(self.prev_span),
@@ -3154,10 +3152,11 @@ impl<'a> Parser<'a> {
 
         let attrs = self.parse_outer_attributes()?;
         let pats = self.parse_pats()?;
-        let mut guard = None;
-        if self.eat_keyword(keywords::If) {
-            guard = Some(self.parse_expr()?);
-        }
+        let guard = if self.eat_keyword(keywords::If) {
+            Some(self.parse_expr()?)
+        } else {
+            None
+        };
         self.expect(&token::FatArrow)?;
         let expr = self.parse_expr_res(RESTRICTION_STMT_EXPR, None)?;
 
@@ -3600,10 +3599,11 @@ impl<'a> Parser<'a> {
         let lo = self.span;
         let pat = self.parse_pat()?;
 
-        let mut ty = None;
-        if self.eat(&token::Colon) {
-            ty = Some(self.parse_ty()?);
-        }
+        let ty = if self.eat(&token::Colon) {
+            Some(self.parse_ty()?)
+        } else {
+            None
+        };
         let init = self.parse_initializer()?;
         Ok(P(ast::Local {
             ty: ty,
@@ -3929,7 +3929,7 @@ impl<'a> Parser<'a> {
                 },
                 None => {
                     let unused_attrs = |attrs: &[_], s: &mut Self| {
-                        if attrs.len() > 0 {
+                        if !attrs.is_empty() {
                             if s.prev_token_kind == PrevTokenKind::DocComment {
                                 s.span_fatal_err(s.prev_span, Error::UselessDocComment).emit();
                             } else {
@@ -4815,7 +4815,7 @@ impl<'a> Parser<'a> {
                 self.expect(&token::Not)?;
             }
 
-            self.complain_if_pub_macro(&vis, prev_span);
+            self.complain_if_pub_macro(vis, prev_span);
 
             // eat a matched-delimiter token tree:
             *at_end = true;
@@ -4917,13 +4917,10 @@ impl<'a> Parser<'a> {
                 }
             }
         } else {
-            match polarity {
-                ast::ImplPolarity::Negative => {
-                    // This is a negated type implementation
-                    // `impl !MyType {}`, which is not allowed.
-                    self.span_err(neg_span, "inherent implementation can't be negated");
-                },
-                _ => {}
+            if let ast::ImplPolarity::Negative = polarity {
+                // This is a negated type implementation
+                // `impl !MyType {}`, which is not allowed.
+                self.span_err(neg_span, "inherent implementation can't be negated");
             }
             None
         };
@@ -5185,7 +5182,7 @@ impl<'a> Parser<'a> {
                 let path_span = self.prev_span;
                 let help_msg = format!("make this visible only to module `{}` with `in`:", path);
                 self.expect(&token::CloseDelim(token::Paren))?;  // `)`
-                let mut err = self.span_fatal_help(path_span, &msg, &suggestion);
+                let mut err = self.span_fatal_help(path_span, msg, suggestion);
                 err.span_suggestion(path_span, &help_msg, format!("in {}", path));
                 err.emit();  // emit diagnostic, but continue with public visibility
             }
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 25cabef70c1..77db604c56e 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -53,6 +53,10 @@ impl DelimToken {
     pub fn len(self) -> usize {
         if self == NoDelim { 0 } else { 1 }
     }
+
+    pub fn is_empty(self) -> bool {
+        self == NoDelim
+    }
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
@@ -198,17 +202,17 @@ impl Token {
     pub fn can_begin_expr(&self) -> bool {
         match *self {
             Ident(ident)                => ident_can_begin_expr(ident), // value name or keyword
-            OpenDelim(..)               => true, // tuple, array or block
-            Literal(..)                 => true, // literal
-            Not                         => true, // operator not
-            BinOp(Minus)                => true, // unary minus
-            BinOp(Star)                 => true, // dereference
-            BinOp(Or) | OrOr            => true, // closure
-            BinOp(And)                  => true, // reference
-            AndAnd                      => true, // double reference
-            DotDot | DotDotDot          => true, // range notation
-            Lt | BinOp(Shl)             => true, // associated path
-            ModSep                      => true, // global path
+            OpenDelim(..)               | // tuple, array or block
+            Literal(..)                 | // literal
+            Not                         | // operator not
+            BinOp(Minus)                | // unary minus
+            BinOp(Star)                 | // dereference
+            BinOp(Or) | OrOr            | // closure
+            BinOp(And)                  | // reference
+            AndAnd                      | // double reference
+            DotDot | DotDotDot          | // range notation
+            Lt | BinOp(Shl)             | // associated path
+            ModSep                      | // global path
             Pound                       => true, // expression attributes
             Interpolated(ref nt) => match **nt {
                 NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) => true,
@@ -222,16 +226,16 @@ impl Token {
     pub fn can_begin_type(&self) -> bool {
         match *self {
             Ident(ident)                => ident_can_begin_type(ident), // type name or keyword
-            OpenDelim(Paren)            => true, // tuple
-            OpenDelim(Bracket)          => true, // array
-            Underscore                  => true, // placeholder
-            Not                         => true, // never
-            BinOp(Star)                 => true, // raw pointer
-            BinOp(And)                  => true, // reference
-            AndAnd                      => true, // double reference
-            Question                    => true, // maybe bound in trait object
-            Lifetime(..)                => true, // lifetime bound in trait object
-            Lt | BinOp(Shl)             => true, // associated path
+            OpenDelim(Paren)            | // tuple
+            OpenDelim(Bracket)          | // array
+            Underscore                  | // placeholder
+            Not                         | // never
+            BinOp(Star)                 | // raw pointer
+            BinOp(And)                  | // reference
+            AndAnd                      | // double reference
+            Question                    | // maybe bound in trait object
+            Lifetime(..)                | // lifetime bound in trait object
+            Lt | BinOp(Shl)             | // associated path
             ModSep                      => true, // global path
             Interpolated(ref nt) => match **nt {
                 NtIdent(..) | NtTy(..) | NtPath(..) => true,
diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs
index 1d67c2a2c2b..e893c859247 100644
--- a/src/libsyntax/print/pp.rs
+++ b/src/libsyntax/print/pp.rs
@@ -113,22 +113,22 @@
 //! between using 'left' and 'right' terms to denote the wrapped-to-ring-buffer
 //! and point-in-infinite-stream senses freely.
 //!
-//! There is a parallel ring buffer, 'size', that holds the calculated size of
+//! There is a parallel ring buffer, `size`, that holds the calculated size of
 //! each token. Why calculated? Because for Begin/End pairs, the "size"
 //! includes everything between the pair. That is, the "size" of Begin is
 //! actually the sum of the sizes of everything between Begin and the paired
-//! End that follows. Since that is arbitrarily far in the future, 'size' is
+//! End that follows. Since that is arbitrarily far in the future, `size` is
 //! being rewritten regularly while the printer runs; in fact most of the
-//! machinery is here to work out 'size' entries on the fly (and give up when
+//! machinery is here to work out `size` entries on the fly (and give up when
 //! they're so obviously over-long that "infinity" is a good enough
 //! approximation for purposes of line breaking).
 //!
 //! The "input side" of the printer is managed as an abstract process called
-//! SCAN, which uses 'scan_stack', to manage calculating 'size'. SCAN is, in
+//! SCAN, which uses `scan_stack`, to manage calculating `size`. SCAN is, in
 //! other words, the process of calculating 'size' entries.
 //!
 //! The "output side" of the printer is managed by an abstract process called
-//! PRINT, which uses 'print_stack', 'margin' and 'space' to figure out what to
+//! PRINT, which uses `print_stack`, `margin` and `space` to figure out what to
 //! do with each token/size pair it consumes as it goes. It's trying to consume
 //! the entire buffered window, but can't output anything until the size is >=
 //! 0 (sizes are set to negative while they're pending calculation).
@@ -409,7 +409,7 @@ impl<'a> Printer<'a> {
     pub fn advance_right(&mut self) {
         self.right += 1;
         self.right %= self.buf_len;
-        assert!(self.right != self.left);
+        assert_ne!(self.right, self.left);
     }
     pub fn advance_left(&mut self) -> io::Result<()> {
         debug!("advance_left Vec<{},{}>, sizeof({})={}", self.left, self.right,
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 0c7e8fda837..6114db25fe8 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -233,7 +233,7 @@ pub fn token_to_string(tok: &Token) -> String {
         token::CloseDelim(token::Bracket) => "]".to_string(),
         token::OpenDelim(token::Brace) => "{".to_string(),
         token::CloseDelim(token::Brace) => "}".to_string(),
-        token::OpenDelim(token::NoDelim) => " ".to_string(),
+        token::OpenDelim(token::NoDelim) |
         token::CloseDelim(token::NoDelim) => " ".to_string(),
         token::Pound                => "#".to_string(),
         token::Dollar               => "$".to_string(),
@@ -244,7 +244,7 @@ pub fn token_to_string(tok: &Token) -> String {
             let mut out = match lit {
                 token::Byte(b)           => format!("b'{}'", b),
                 token::Char(c)           => format!("'{}'", c),
-                token::Float(c)          => c.to_string(),
+                token::Float(c)          |
                 token::Integer(c)        => c.to_string(),
                 token::Str_(s)           => format!("\"{}\"", s),
                 token::StrRaw(s, n)      => format!("r{delim}\"{string}\"{delim}",
@@ -277,23 +277,23 @@ pub fn token_to_string(tok: &Token) -> String {
         token::Shebang(s)           => format!("/* shebang: {}*/", s),
 
         token::Interpolated(ref nt) => match **nt {
-            token::NtExpr(ref e)        => expr_to_string(&e),
-            token::NtMeta(ref e)        => meta_item_to_string(&e),
-            token::NtTy(ref e)          => ty_to_string(&e),
-            token::NtPath(ref e)        => path_to_string(&e),
-            token::NtItem(ref e)        => item_to_string(&e),
-            token::NtBlock(ref e)       => block_to_string(&e),
-            token::NtStmt(ref e)        => stmt_to_string(&e),
-            token::NtPat(ref e)         => pat_to_string(&e),
+            token::NtExpr(ref e)        => expr_to_string(e),
+            token::NtMeta(ref e)        => meta_item_to_string(e),
+            token::NtTy(ref e)          => ty_to_string(e),
+            token::NtPath(ref e)        => path_to_string(e),
+            token::NtItem(ref e)        => item_to_string(e),
+            token::NtBlock(ref e)       => block_to_string(e),
+            token::NtStmt(ref e)        => stmt_to_string(e),
+            token::NtPat(ref e)         => pat_to_string(e),
             token::NtIdent(ref e)       => ident_to_string(e.node),
             token::NtTT(ref tree)       => tt_to_string(tree.clone()),
-            token::NtArm(ref e)         => arm_to_string(&e),
-            token::NtImplItem(ref e)    => impl_item_to_string(&e),
-            token::NtTraitItem(ref e)   => trait_item_to_string(&e),
-            token::NtGenerics(ref e)    => generics_to_string(&e),
-            token::NtWhereClause(ref e) => where_clause_to_string(&e),
-            token::NtArg(ref e)         => arg_to_string(&e),
-            token::NtVis(ref e)         => vis_to_string(&e),
+            token::NtArm(ref e)         => arm_to_string(e),
+            token::NtImplItem(ref e)    => impl_item_to_string(e),
+            token::NtTraitItem(ref e)   => trait_item_to_string(e),
+            token::NtGenerics(ref e)    => generics_to_string(e),
+            token::NtWhereClause(ref e) => where_clause_to_string(e),
+            token::NtArg(ref e)         => arg_to_string(e),
+            token::NtVis(ref e)         => vis_to_string(e),
         }
     }
 }
@@ -520,8 +520,7 @@ pub trait PrintState<'a> {
 
         let mut result = None;
 
-        if let &Some(ref lits) = self.literals()
-        {
+        if let Some(ref lits) = *self.literals() {
             while cur_lit < lits.len() {
                 let ltrl = (*lits)[cur_lit].clone();
                 if ltrl.pos > pos { break; }
@@ -618,11 +617,8 @@ pub trait PrintState<'a> {
 
     fn print_literal(&mut self, lit: &ast::Lit) -> io::Result<()> {
         self.maybe_print_comment(lit.span.lo)?;
-        match self.next_lit(lit.span.lo) {
-            Some(ref ltrl) => {
-                return word(self.writer(), &(*ltrl).lit);
-            }
-            _ => ()
+        if let Some(ref ltrl) = self.next_lit(lit.span.lo) {
+            return word(self.writer(), &(*ltrl).lit);
         }
         match lit.node {
             ast::LitKind::Str(st, style) => self.print_string(&st.as_str(), style),
@@ -799,7 +795,7 @@ pub trait PrintState<'a> {
                 self.popen()?;
                 self.commasep(Consistent,
                               &items[..],
-                              |s, i| s.print_meta_list_item(&i))?;
+                              |s, i| s.print_meta_list_item(i))?;
                 self.pclose()?;
             }
         }
@@ -965,11 +961,9 @@ impl<'a> State<'a> {
     {
         self.rbox(0, b)?;
         let len = elts.len();
-        let mut i = 0;
-        for elt in elts {
+        for (i, elt) in elts.iter().enumerate() {
             self.maybe_print_comment(get_span(elt).hi)?;
             op(self, elt)?;
-            i += 1;
             if i < len {
                 word(&mut self.s, ",")?;
                 self.maybe_print_trailing_comment(get_span(elt),
@@ -982,14 +976,14 @@ impl<'a> State<'a> {
 
     pub fn commasep_exprs(&mut self, b: Breaks,
                           exprs: &[P]) -> io::Result<()> {
-        self.commasep_cmnt(b, exprs, |s, e| s.print_expr(&e), |e| e.span)
+        self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span)
     }
 
     pub fn print_mod(&mut self, _mod: &ast::Mod,
                      attrs: &[ast::Attribute]) -> io::Result<()> {
         self.print_inner_attributes(attrs)?;
         for item in &_mod.items {
-            self.print_item(&item)?;
+            self.print_item(item)?;
         }
         Ok(())
     }
@@ -1018,7 +1012,7 @@ impl<'a> State<'a> {
         match ty.node {
             ast::TyKind::Slice(ref ty) => {
                 word(&mut self.s, "[")?;
-                self.print_type(&ty)?;
+                self.print_type(ty)?;
                 word(&mut self.s, "]")?;
             }
             ast::TyKind::Ptr(ref mt) => {
@@ -1040,7 +1034,7 @@ impl<'a> State<'a> {
             ast::TyKind::Tup(ref elts) => {
                 self.popen()?;
                 self.commasep(Inconsistent, &elts[..],
-                              |s, ty| s.print_type(&ty))?;
+                              |s, ty| s.print_type(ty))?;
                 if elts.len() == 1 {
                     word(&mut self.s, ",")?;
                 }
@@ -1048,7 +1042,7 @@ impl<'a> State<'a> {
             }
             ast::TyKind::Paren(ref typ) => {
                 self.popen()?;
-                self.print_type(&typ)?;
+                self.print_type(typ)?;
                 self.pclose()?;
             }
             ast::TyKind::BareFn(ref f) => {
@@ -1081,14 +1075,14 @@ impl<'a> State<'a> {
             }
             ast::TyKind::Array(ref ty, ref v) => {
                 word(&mut self.s, "[")?;
-                self.print_type(&ty)?;
+                self.print_type(ty)?;
                 word(&mut self.s, "; ")?;
-                self.print_expr(&v)?;
+                self.print_expr(v)?;
                 word(&mut self.s, "]")?;
             }
             ast::TyKind::Typeof(ref e) => {
                 word(&mut self.s, "typeof(")?;
-                self.print_expr(&e)?;
+                self.print_expr(e)?;
                 word(&mut self.s, ")")?;
             }
             ast::TyKind::Infer => {
@@ -1130,7 +1124,7 @@ impl<'a> State<'a> {
                 }
                 self.print_ident(item.ident)?;
                 self.word_space(":")?;
-                self.print_type(&t)?;
+                self.print_type(t)?;
                 word(&mut self.s, ";")?;
                 self.end()?; // end the head-ibox
                 self.end() // end the outer cbox
@@ -1187,7 +1181,7 @@ impl<'a> State<'a> {
                 self.head(&visibility_qualified(&item.vis, "extern crate"))?;
                 if let Some(p) = *optional_path {
                     let val = p.as_str();
-                    if val.contains("-") {
+                    if val.contains('-') {
                         self.print_string(&val, ast::StrStyle::Cooked)?;
                     } else {
                         self.print_name(p)?;
@@ -1203,7 +1197,7 @@ impl<'a> State<'a> {
             }
             ast::ItemKind::Use(ref vp) => {
                 self.head(&visibility_qualified(&item.vis, "use"))?;
-                self.print_view_path(&vp)?;
+                self.print_view_path(vp)?;
                 word(&mut self.s, ";")?;
                 self.end()?; // end inner head-block
                 self.end()?; // end outer head-block
@@ -1215,12 +1209,12 @@ impl<'a> State<'a> {
                 }
                 self.print_ident(item.ident)?;
                 self.word_space(":")?;
-                self.print_type(&ty)?;
+                self.print_type(ty)?;
                 space(&mut self.s)?;
                 self.end()?; // end the head-ibox
 
                 self.word_space("=")?;
-                self.print_expr(&expr)?;
+                self.print_expr(expr)?;
                 word(&mut self.s, ";")?;
                 self.end()?; // end the outer cbox
             }
@@ -1228,12 +1222,12 @@ impl<'a> State<'a> {
                 self.head(&visibility_qualified(&item.vis, "const"))?;
                 self.print_ident(item.ident)?;
                 self.word_space(":")?;
-                self.print_type(&ty)?;
+                self.print_type(ty)?;
                 space(&mut self.s)?;
                 self.end()?; // end the head-ibox
 
                 self.word_space("=")?;
-                self.print_expr(&expr)?;
+                self.print_expr(expr)?;
                 word(&mut self.s, ";")?;
                 self.end()?; // end the outer cbox
             }
@@ -1249,7 +1243,7 @@ impl<'a> State<'a> {
                     &item.vis
                 )?;
                 word(&mut self.s, " ")?;
-                self.print_block_with_attrs(&body, &item.attrs)?;
+                self.print_block_with_attrs(body, &item.attrs)?;
             }
             ast::ItemKind::Mod(ref _mod) => {
                 self.head(&visibility_qualified(&item.vis, "mod"))?;
@@ -1282,7 +1276,7 @@ impl<'a> State<'a> {
                 self.print_where_clause(¶ms.where_clause)?;
                 space(&mut self.s)?;
                 self.word_space("=")?;
-                self.print_type(&ty)?;
+                self.print_type(ty)?;
                 word(&mut self.s, ";")?;
                 self.end()?; // end the outer ibox
             }
@@ -1297,11 +1291,11 @@ impl<'a> State<'a> {
             }
             ast::ItemKind::Struct(ref struct_def, ref generics) => {
                 self.head(&visibility_qualified(&item.vis, "struct"))?;
-                self.print_struct(&struct_def, generics, item.ident, item.span, true)?;
+                self.print_struct(struct_def, generics, item.ident, item.span, true)?;
             }
             ast::ItemKind::Union(ref struct_def, ref generics) => {
                 self.head(&visibility_qualified(&item.vis, "union"))?;
-                self.print_struct(&struct_def, generics, item.ident, item.span, true)?;
+                self.print_struct(struct_def, generics, item.ident, item.span, true)?;
             }
             ast::ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
                 self.head("")?;
@@ -1333,11 +1327,8 @@ impl<'a> State<'a> {
                     space(&mut self.s)?;
                 }
 
-                match polarity {
-                    ast::ImplPolarity::Negative => {
-                        word(&mut self.s, "!")?;
-                    },
-                    _ => {}
+                if let ast::ImplPolarity::Negative = polarity {
+                    word(&mut self.s, "!")?;
                 }
 
                 if let Some(ref t) = *opt_trait {
@@ -1346,7 +1337,7 @@ impl<'a> State<'a> {
                     self.word_space("for")?;
                 }
 
-                self.print_type(&ty)?;
+                self.print_type(ty)?;
                 self.print_where_clause(&generics.where_clause)?;
 
                 space(&mut self.s)?;
@@ -1543,7 +1534,7 @@ impl<'a> State<'a> {
             Some(ref d) => {
                 space(&mut self.s)?;
                 self.word_space("=")?;
-                self.print_expr(&d)
+                self.print_expr(d)
             }
             _ => Ok(())
         }
@@ -1571,7 +1562,7 @@ impl<'a> State<'a> {
         self.print_outer_attributes(&ti.attrs)?;
         match ti.node {
             ast::TraitItemKind::Const(ref ty, ref default) => {
-                self.print_associated_const(ti.ident, &ty,
+                self.print_associated_const(ti.ident, ty,
                                             default.as_ref().map(|expr| &**expr),
                                             &ast::Visibility::Inherited)?;
             }
@@ -1614,7 +1605,7 @@ impl<'a> State<'a> {
         self.print_defaultness(ii.defaultness)?;
         match ii.node {
             ast::ImplItemKind::Const(ref ty, ref expr) => {
-                self.print_associated_const(ii.ident, &ty, Some(&expr), &ii.vis)?;
+                self.print_associated_const(ii.ident, ty, Some(expr), &ii.vis)?;
             }
             ast::ImplItemKind::Method(ref sig, ref body) => {
                 self.head("")?;
@@ -1650,38 +1641,38 @@ impl<'a> State<'a> {
                 self.word_nbsp("let")?;
 
                 self.ibox(INDENT_UNIT)?;
-                self.print_local_decl(&loc)?;
+                self.print_local_decl(loc)?;
                 self.end()?;
                 if let Some(ref init) = loc.init {
                     self.nbsp()?;
                     self.word_space("=")?;
-                    self.print_expr(&init)?;
+                    self.print_expr(init)?;
                 }
                 word(&mut self.s, ";")?;
                 self.end()?;
             }
-            ast::StmtKind::Item(ref item) => self.print_item(&item)?,
+            ast::StmtKind::Item(ref item) => self.print_item(item)?,
             ast::StmtKind::Expr(ref expr) => {
                 self.space_if_not_bol()?;
-                self.print_expr_outer_attr_style(&expr, false)?;
+                self.print_expr_outer_attr_style(expr, false)?;
                 if parse::classify::expr_requires_semi_to_be_stmt(expr) {
                     word(&mut self.s, ";")?;
                 }
             }
             ast::StmtKind::Semi(ref expr) => {
                 self.space_if_not_bol()?;
-                self.print_expr_outer_attr_style(&expr, false)?;
+                self.print_expr_outer_attr_style(expr, false)?;
                 word(&mut self.s, ";")?;
             }
             ast::StmtKind::Mac(ref mac) => {
                 let (ref mac, style, ref attrs) = **mac;
                 self.space_if_not_bol()?;
-                self.print_outer_attributes(&attrs)?;
+                self.print_outer_attributes(attrs)?;
                 let delim = match style {
                     ast::MacStmtStyle::Braces => token::Brace,
                     _ => token::Paren
                 };
-                self.print_mac(&mac, delim)?;
+                self.print_mac(mac, delim)?;
                 if style == ast::MacStmtStyle::Semicolon {
                     word(&mut self.s, ";")?;
                 }
@@ -1735,7 +1726,7 @@ impl<'a> State<'a> {
                 ast::StmtKind::Expr(ref expr) if i == blk.stmts.len() - 1 => {
                     self.maybe_print_comment(st.span.lo)?;
                     self.space_if_not_bol()?;
-                    self.print_expr_outer_attr_style(&expr, false)?;
+                    self.print_expr_outer_attr_style(expr, false)?;
                     self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi))?;
                 }
                 _ => self.print_stmt(st)?,
@@ -1755,9 +1746,9 @@ impl<'a> State<'a> {
                         self.cbox(INDENT_UNIT - 1)?;
                         self.ibox(0)?;
                         word(&mut self.s, " else if ")?;
-                        self.print_expr(&i)?;
+                        self.print_expr(i)?;
                         space(&mut self.s)?;
-                        self.print_block(&then)?;
+                        self.print_block(then)?;
                         self.print_else(e.as_ref().map(|e| &**e))
                     }
                     // "another else-if-let"
@@ -1765,12 +1756,12 @@ impl<'a> State<'a> {
                         self.cbox(INDENT_UNIT - 1)?;
                         self.ibox(0)?;
                         word(&mut self.s, " else if let ")?;
-                        self.print_pat(&pat)?;
+                        self.print_pat(pat)?;
                         space(&mut self.s)?;
                         self.word_space("=")?;
-                        self.print_expr(&expr)?;
+                        self.print_expr(expr)?;
                         space(&mut self.s)?;
-                        self.print_block(&then)?;
+                        self.print_block(then)?;
                         self.print_else(e.as_ref().map(|e| &**e))
                     }
                     // "final else"
@@ -1778,7 +1769,7 @@ impl<'a> State<'a> {
                         self.cbox(INDENT_UNIT - 1)?;
                         self.ibox(0)?;
                         word(&mut self.s, " else ")?;
-                        self.print_block(&b)
+                        self.print_block(b)
                     }
                     // BLEAH, constraints would be great here
                     _ => {
@@ -1844,12 +1835,8 @@ impl<'a> State<'a> {
                                       binop: ast::BinOp) -> bool {
         match sub_expr.node {
             ast::ExprKind::Binary(ref sub_op, _, _) => {
-                if AssocOp::from_ast_binop(sub_op.node).precedence() <
-                    AssocOp::from_ast_binop(binop.node).precedence() {
-                    true
-                } else {
-                    false
-                }
+                AssocOp::from_ast_binop(sub_op.node).precedence() <
+                    AssocOp::from_ast_binop(binop.node).precedence()
             }
             _ => true
         }
@@ -1929,7 +1916,7 @@ impl<'a> State<'a> {
                     space(&mut self.s)?;
                 }
                 word(&mut self.s, "..")?;
-                self.print_expr(&expr)?;
+                self.print_expr(expr)?;
                 self.end()?;
             }
             _ => if !fields.is_empty() {
@@ -1969,7 +1956,7 @@ impl<'a> State<'a> {
         if !tys.is_empty() {
             word(&mut self.s, "::<")?;
             self.commasep(Inconsistent, tys,
-                          |s, ty| s.print_type(&ty))?;
+                          |s, ty| s.print_type(ty))?;
             word(&mut self.s, ">")?;
         }
         self.print_call_post(base_args)
@@ -2038,7 +2025,7 @@ impl<'a> State<'a> {
                 self.print_expr_vec(&exprs[..], attrs)?;
             }
             ast::ExprKind::Repeat(ref element, ref count) => {
-                self.print_expr_repeat(&element, &count, attrs)?;
+                self.print_expr_repeat(element, count, attrs)?;
             }
             ast::ExprKind::Struct(ref path, ref fields, ref wth) => {
                 self.print_expr_struct(path, &fields[..], wth, attrs)?;
@@ -2047,43 +2034,43 @@ impl<'a> State<'a> {
                 self.print_expr_tup(&exprs[..], attrs)?;
             }
             ast::ExprKind::Call(ref func, ref args) => {
-                self.print_expr_call(&func, &args[..])?;
+                self.print_expr_call(func, &args[..])?;
             }
             ast::ExprKind::MethodCall(ident, ref tys, ref args) => {
                 self.print_expr_method_call(ident, &tys[..], &args[..])?;
             }
             ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
-                self.print_expr_binary(op, &lhs, &rhs)?;
+                self.print_expr_binary(op, lhs, rhs)?;
             }
             ast::ExprKind::Unary(op, ref expr) => {
-                self.print_expr_unary(op, &expr)?;
+                self.print_expr_unary(op, expr)?;
             }
             ast::ExprKind::AddrOf(m, ref expr) => {
-                self.print_expr_addr_of(m, &expr)?;
+                self.print_expr_addr_of(m, expr)?;
             }
             ast::ExprKind::Lit(ref lit) => {
-                self.print_literal(&lit)?;
+                self.print_literal(lit)?;
             }
             ast::ExprKind::Cast(ref expr, ref ty) => {
                 if let ast::ExprKind::Cast(..) = expr.node {
-                    self.print_expr(&expr)?;
+                    self.print_expr(expr)?;
                 } else {
-                    self.print_expr_maybe_paren(&expr)?;
+                    self.print_expr_maybe_paren(expr)?;
                 }
                 space(&mut self.s)?;
                 self.word_space("as")?;
-                self.print_type(&ty)?;
+                self.print_type(ty)?;
             }
             ast::ExprKind::Type(ref expr, ref ty) => {
-                self.print_expr(&expr)?;
+                self.print_expr(expr)?;
                 self.word_space(":")?;
-                self.print_type(&ty)?;
+                self.print_type(ty)?;
             }
             ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
-                self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?;
+                self.print_if(test, blk, elseopt.as_ref().map(|e| &**e))?;
             }
             ast::ExprKind::IfLet(ref pat, ref expr, ref blk, ref elseopt) => {
-                self.print_if_let(&pat, &expr, &blk, elseopt.as_ref().map(|e| &**e))?;
+                self.print_if_let(pat, expr, blk, elseopt.as_ref().map(|e| &**e))?;
             }
             ast::ExprKind::While(ref test, ref blk, opt_ident) => {
                 if let Some(ident) = opt_ident {
@@ -2091,9 +2078,9 @@ impl<'a> State<'a> {
                     self.word_space(":")?;
                 }
                 self.head("while")?;
-                self.print_expr(&test)?;
+                self.print_expr(test)?;
                 space(&mut self.s)?;
-                self.print_block_with_attrs(&blk, attrs)?;
+                self.print_block_with_attrs(blk, attrs)?;
             }
             ast::ExprKind::WhileLet(ref pat, ref expr, ref blk, opt_ident) => {
                 if let Some(ident) = opt_ident {
@@ -2101,12 +2088,12 @@ impl<'a> State<'a> {
                     self.word_space(":")?;
                 }
                 self.head("while let")?;
-                self.print_pat(&pat)?;
+                self.print_pat(pat)?;
                 space(&mut self.s)?;
                 self.word_space("=")?;
-                self.print_expr(&expr)?;
+                self.print_expr(expr)?;
                 space(&mut self.s)?;
-                self.print_block_with_attrs(&blk, attrs)?;
+                self.print_block_with_attrs(blk, attrs)?;
             }
             ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_ident) => {
                 if let Some(ident) = opt_ident {
@@ -2114,12 +2101,12 @@ impl<'a> State<'a> {
                     self.word_space(":")?;
                 }
                 self.head("for")?;
-                self.print_pat(&pat)?;
+                self.print_pat(pat)?;
                 space(&mut self.s)?;
                 self.word_space("in")?;
-                self.print_expr(&iter)?;
+                self.print_expr(iter)?;
                 space(&mut self.s)?;
-                self.print_block_with_attrs(&blk, attrs)?;
+                self.print_block_with_attrs(blk, attrs)?;
             }
             ast::ExprKind::Loop(ref blk, opt_ident) => {
                 if let Some(ident) = opt_ident {
@@ -2128,13 +2115,13 @@ impl<'a> State<'a> {
                 }
                 self.head("loop")?;
                 space(&mut self.s)?;
-                self.print_block_with_attrs(&blk, attrs)?;
+                self.print_block_with_attrs(blk, attrs)?;
             }
             ast::ExprKind::Match(ref expr, ref arms) => {
                 self.cbox(INDENT_UNIT)?;
                 self.ibox(4)?;
                 self.word_nbsp("match")?;
-                self.print_expr(&expr)?;
+                self.print_expr(expr)?;
                 space(&mut self.s)?;
                 self.bopen()?;
                 self.print_inner_attributes_no_trailing_hardbreak(attrs)?;
@@ -2146,7 +2133,7 @@ impl<'a> State<'a> {
             ast::ExprKind::Closure(capture_clause, ref decl, ref body, _) => {
                 self.print_capture_clause(capture_clause)?;
 
-                self.print_fn_block_args(&decl)?;
+                self.print_fn_block_args(decl)?;
                 space(&mut self.s)?;
                 self.print_expr(body)?;
                 self.end()?; // need to close a box
@@ -2161,48 +2148,48 @@ impl<'a> State<'a> {
                 self.cbox(INDENT_UNIT)?;
                 // head-box, will be closed by print-block after {
                 self.ibox(0)?;
-                self.print_block_with_attrs(&blk, attrs)?;
+                self.print_block_with_attrs(blk, attrs)?;
             }
             ast::ExprKind::Assign(ref lhs, ref rhs) => {
-                self.print_expr(&lhs)?;
+                self.print_expr(lhs)?;
                 space(&mut self.s)?;
                 self.word_space("=")?;
-                self.print_expr(&rhs)?;
+                self.print_expr(rhs)?;
             }
             ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
-                self.print_expr(&lhs)?;
+                self.print_expr(lhs)?;
                 space(&mut self.s)?;
                 word(&mut self.s, op.node.to_string())?;
                 self.word_space("=")?;
-                self.print_expr(&rhs)?;
+                self.print_expr(rhs)?;
             }
             ast::ExprKind::Field(ref expr, id) => {
-                self.print_expr(&expr)?;
+                self.print_expr(expr)?;
                 word(&mut self.s, ".")?;
                 self.print_ident(id.node)?;
             }
             ast::ExprKind::TupField(ref expr, id) => {
-                self.print_expr(&expr)?;
+                self.print_expr(expr)?;
                 word(&mut self.s, ".")?;
                 self.print_usize(id.node)?;
             }
             ast::ExprKind::Index(ref expr, ref index) => {
-                self.print_expr(&expr)?;
+                self.print_expr(expr)?;
                 word(&mut self.s, "[")?;
-                self.print_expr(&index)?;
+                self.print_expr(index)?;
                 word(&mut self.s, "]")?;
             }
             ast::ExprKind::Range(ref start, ref end, limits) => {
-                if let &Some(ref e) = start {
-                    self.print_expr(&e)?;
+                if let Some(ref e) = *start {
+                    self.print_expr(e)?;
                 }
                 if limits == ast::RangeLimits::HalfOpen {
                     word(&mut self.s, "..")?;
                 } else {
                     word(&mut self.s, "...")?;
                 }
-                if let &Some(ref e) = end {
-                    self.print_expr(&e)?;
+                if let Some(ref e) = *end {
+                    self.print_expr(e)?;
                 }
             }
             ast::ExprKind::Path(None, ref path) => {
@@ -2233,12 +2220,9 @@ impl<'a> State<'a> {
             }
             ast::ExprKind::Ret(ref result) => {
                 word(&mut self.s, "return")?;
-                match *result {
-                    Some(ref expr) => {
-                        word(&mut self.s, " ")?;
-                        self.print_expr(&expr)?;
-                    }
-                    _ => ()
+                if let Some(ref expr) = *result {
+                    word(&mut self.s, " ")?;
+                    self.print_expr(expr)?;
                 }
             }
             ast::ExprKind::InlineAsm(ref a) => {
@@ -2268,7 +2252,7 @@ impl<'a> State<'a> {
                 self.commasep(Inconsistent, &a.inputs, |s, &(co, ref o)| {
                     s.print_string(&co.as_str(), ast::StrStyle::Cooked)?;
                     s.popen()?;
-                    s.print_expr(&o)?;
+                    s.print_expr(o)?;
                     s.pclose()?;
                     Ok(())
                 })?;
@@ -2308,7 +2292,7 @@ impl<'a> State<'a> {
             ast::ExprKind::Paren(ref e) => {
                 self.popen()?;
                 self.print_inner_attributes_inline(attrs)?;
-                self.print_expr(&e)?;
+                self.print_expr(e)?;
                 self.pclose()?;
             },
             ast::ExprKind::Try(ref e) => {
@@ -2318,7 +2302,7 @@ impl<'a> State<'a> {
             ast::ExprKind::Catch(ref blk) => {
                 self.head("do catch")?;
                 space(&mut self.s)?;
-                self.print_block_with_attrs(&blk, attrs)?
+                self.print_block_with_attrs(blk, attrs)?
             }
         }
         self.ann.post(self, NodeExpr(expr))?;
@@ -2329,7 +2313,7 @@ impl<'a> State<'a> {
         self.print_pat(&loc.pat)?;
         if let Some(ref ty) = loc.ty {
             self.word_space(":")?;
-            self.print_type(&ty)?;
+            self.print_type(ty)?;
         }
         Ok(())
     }
@@ -2397,7 +2381,7 @@ impl<'a> State<'a> {
             space(&mut self.s)?;
             self.word_space("as")?;
             let depth = path.segments.len() - qself.position;
-            self.print_path(&path, false, depth, false)?;
+            self.print_path(path, false, depth, false)?;
         }
         word(&mut self.s, ">")?;
         word(&mut self.s, "::")?;
@@ -2438,7 +2422,7 @@ impl<'a> State<'a> {
                     self.commasep(
                         Inconsistent,
                         &data.types,
-                        |s, ty| s.print_type(&ty))?;
+                        |s, ty| s.print_type(ty))?;
                         comma = true;
                 }
 
@@ -2461,13 +2445,13 @@ impl<'a> State<'a> {
                 self.commasep(
                     Inconsistent,
                     &data.inputs,
-                    |s, ty| s.print_type(&ty))?;
+                    |s, ty| s.print_type(ty))?;
                 word(&mut self.s, ")")?;
 
                 if let Some(ref ty) = data.output {
                     self.space_if_not_bol()?;
                     self.word_space("->")?;
-                    self.print_type(&ty)?;
+                    self.print_type(ty)?;
                 }
             }
         }
@@ -2496,24 +2480,24 @@ impl<'a> State<'a> {
                 self.print_ident(path1.node)?;
                 if let Some(ref p) = *sub {
                     word(&mut self.s, "@")?;
-                    self.print_pat(&p)?;
+                    self.print_pat(p)?;
                 }
             }
             PatKind::TupleStruct(ref path, ref elts, ddpos) => {
                 self.print_path(path, true, 0, false)?;
                 self.popen()?;
                 if let Some(ddpos) = ddpos {
-                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?;
+                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p))?;
                     if ddpos != 0 {
                         self.word_space(",")?;
                     }
                     word(&mut self.s, "..")?;
                     if ddpos != elts.len() {
                         word(&mut self.s, ",")?;
-                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?;
+                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(p))?;
                     }
                 } else {
-                    self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?;
+                    self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p))?;
                 }
                 self.pclose()?;
             }
@@ -2549,17 +2533,17 @@ impl<'a> State<'a> {
             PatKind::Tuple(ref elts, ddpos) => {
                 self.popen()?;
                 if let Some(ddpos) = ddpos {
-                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?;
+                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p))?;
                     if ddpos != 0 {
                         self.word_space(",")?;
                     }
                     word(&mut self.s, "..")?;
                     if ddpos != elts.len() {
                         word(&mut self.s, ",")?;
-                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?;
+                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(p))?;
                     }
                 } else {
-                    self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?;
+                    self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p))?;
                     if elts.len() == 1 {
                         word(&mut self.s, ",")?;
                     }
@@ -2568,41 +2552,41 @@ impl<'a> State<'a> {
             }
             PatKind::Box(ref inner) => {
                 word(&mut self.s, "box ")?;
-                self.print_pat(&inner)?;
+                self.print_pat(inner)?;
             }
             PatKind::Ref(ref inner, mutbl) => {
                 word(&mut self.s, "&")?;
                 if mutbl == ast::Mutability::Mutable {
                     word(&mut self.s, "mut ")?;
                 }
-                self.print_pat(&inner)?;
+                self.print_pat(inner)?;
             }
             PatKind::Lit(ref e) => self.print_expr(&**e)?,
             PatKind::Range(ref begin, ref end, ref end_kind) => {
-                self.print_expr(&begin)?;
+                self.print_expr(begin)?;
                 space(&mut self.s)?;
                 match *end_kind {
                     RangeEnd::Included => word(&mut self.s, "...")?,
                     RangeEnd::Excluded => word(&mut self.s, "..")?,
                 }
-                self.print_expr(&end)?;
+                self.print_expr(end)?;
             }
             PatKind::Slice(ref before, ref slice, ref after) => {
                 word(&mut self.s, "[")?;
                 self.commasep(Inconsistent,
                                    &before[..],
-                                   |s, p| s.print_pat(&p))?;
+                                   |s, p| s.print_pat(p))?;
                 if let Some(ref p) = *slice {
                     if !before.is_empty() { self.word_space(",")?; }
                     if p.node != PatKind::Wild {
-                        self.print_pat(&p)?;
+                        self.print_pat(p)?;
                     }
                     word(&mut self.s, "..")?;
                     if !after.is_empty() { self.word_space(",")?; }
                 }
                 self.commasep(Inconsistent,
                                    &after[..],
-                                   |s, p| s.print_pat(&p))?;
+                                   |s, p| s.print_pat(p))?;
                 word(&mut self.s, "]")?;
             }
             PatKind::Mac(ref m) => self.print_mac(m, token::Paren)?,
@@ -2628,12 +2612,12 @@ impl<'a> State<'a> {
                 space(&mut self.s)?;
                 self.word_space("|")?;
             }
-            self.print_pat(&p)?;
+            self.print_pat(p)?;
         }
         space(&mut self.s)?;
         if let Some(ref e) = arm.guard {
             self.word_space("if")?;
-            self.print_expr(&e)?;
+            self.print_expr(e)?;
             space(&mut self.s)?;
         }
         self.word_space("=>")?;
@@ -2641,7 +2625,7 @@ impl<'a> State<'a> {
         match arm.body.node {
             ast::ExprKind::Block(ref blk) => {
                 // the block will close the pattern's ibox
-                self.print_block_unclosed_indent(&blk, INDENT_UNIT)?;
+                self.print_block_unclosed_indent(blk, INDENT_UNIT)?;
 
                 // If it is a user-provided unsafe block, print a comma after it
                 if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
@@ -2673,7 +2657,7 @@ impl<'a> State<'a> {
                 self.print_mutability(m)?;
                 word(&mut self.s, "self")?;
                 self.word_space(":")?;
-                self.print_type(&typ)
+                self.print_type(typ)
             }
         }
     }
@@ -2725,7 +2709,7 @@ impl<'a> State<'a> {
         self.word_space("->")?;
         match decl.output {
             ast::FunctionRetTy::Ty(ref ty) => {
-                self.print_type(&ty)?;
+                self.print_type(ty)?;
                 self.maybe_print_comment(ty.span.lo)
             }
             ast::FunctionRetTy::Default(..) => unreachable!(),
@@ -2839,7 +2823,7 @@ impl<'a> State<'a> {
             Some(ref default) => {
                 space(&mut self.s)?;
                 self.word_space("=")?;
-                self.print_type(&default)
+                self.print_type(default)
             }
             _ => Ok(())
         }
@@ -2865,7 +2849,7 @@ impl<'a> State<'a> {
                                                                              ref bounds,
                                                                              ..}) => {
                     self.print_formal_lifetime_list(bound_lifetimes)?;
-                    self.print_type(&bounded_ty)?;
+                    self.print_type(bounded_ty)?;
                     self.print_bounds(":", bounds)?;
                 }
                 ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
@@ -2977,7 +2961,7 @@ impl<'a> State<'a> {
         match decl.output {
             ast::FunctionRetTy::Default(..) => unreachable!(),
             ast::FunctionRetTy::Ty(ref ty) =>
-                self.print_type(&ty)?
+                self.print_type(ty)?
         }
         self.end()?;
 
@@ -3044,14 +3028,9 @@ impl<'a> State<'a> {
         if self.next_comment().is_none() {
             hardbreak(&mut self.s)?;
         }
-        loop {
-            match self.next_comment() {
-                Some(ref cmnt) => {
-                    self.print_comment(cmnt)?;
-                    self.cur_cmnt_and_lit.cur_cmnt += 1;
-                }
-                _ => break
-            }
+        while let Some(ref cmnt) = self.next_comment() {
+            self.print_comment(cmnt)?;
+            self.cur_cmnt_and_lit.cur_cmnt += 1;
         }
         Ok(())
     }
diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs
index c7820a15fb3..8e257102e1c 100644
--- a/src/libsyntax/std_inject.rs
+++ b/src/libsyntax/std_inject.rs
@@ -18,7 +18,7 @@ use ptr::P;
 use tokenstream::TokenStream;
 
 /// Craft a span that will be ignored by the stability lint's
-/// call to codemap's is_internal check.
+/// call to codemap's `is_internal` check.
 /// The expanded code uses the unstable `#[prelude_import]` attribute.
 fn ignored_span(sp: Span) -> Span {
     let mark = Mark::fresh();
@@ -49,7 +49,7 @@ pub fn maybe_inject_crates_ref(mut krate: ast::Crate, alt_std_name: Option return krate,
     };
 
-    let crate_name = Symbol::intern(&alt_std_name.unwrap_or(name.to_string()));
+    let crate_name = Symbol::intern(&alt_std_name.unwrap_or_else(|| name.to_string()));
 
     krate.module.items.insert(0, P(ast::Item {
         attrs: vec![attr::mk_attr_outer(DUMMY_SP,
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 91746a2edd9..bb1a6ff65a5 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -106,9 +106,8 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
         // Add a special __test module to the crate that will contain code
         // generated for the test harness
         let (mod_, reexport) = mk_test_module(&mut self.cx);
-        match reexport {
-            Some(re) => folded.module.items.push(re),
-            None => {}
+        if let Some(re) = reexport {
+            folded.module.items.push(re)
         }
         folded.module.items.push(mod_);
         folded
@@ -257,7 +256,7 @@ fn mk_reexport_mod(cx: &mut TestCtxt,
     let parent = if parent == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { parent };
     cx.ext_cx.current_expansion.mark = cx.ext_cx.resolver.get_module_scope(parent);
     let it = cx.ext_cx.monotonic_expander().fold_item(P(ast::Item {
-        ident: sym.clone(),
+        ident: sym,
         attrs: Vec::new(),
         id: ast::DUMMY_NODE_ID,
         node: ast::ItemKind::Mod(reexport_mod),
@@ -308,7 +307,7 @@ fn generate_test_harness(sess: &ParseSess,
 }
 
 /// Craft a span that will be ignored by the stability lint's
-/// call to codemap's is_internal check.
+/// call to codemap's `is_internal` check.
 /// The expanded code calls some unstable functions in the test crate.
 fn ignored_span(cx: &TestCtxt, sp: Span) -> Span {
     Span { ctxt: cx.ctxt, ..sp }
@@ -354,7 +353,7 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
         }
     }
 
-    return has_test_attr && has_test_signature(i) == Yes;
+    has_test_attr && has_test_signature(i) == Yes
 }
 
 fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
@@ -385,7 +384,7 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
                       `fn(&mut Bencher) -> ()`");
     }
 
-    return has_bench_attr && has_test_signature(i);
+    has_bench_attr && has_test_signature(i)
 }
 
 fn is_ignored(i: &ast::Item) -> bool {
@@ -504,16 +503,14 @@ fn mk_main(cx: &mut TestCtxt) -> P {
                            ast::Unsafety::Normal,
                            dummy_spanned(ast::Constness::NotConst),
                            ::abi::Abi::Rust, ast::Generics::default(), main_body);
-    let main = P(ast::Item {
+    P(ast::Item {
         ident: Ident::from_str("main"),
         attrs: vec![main_attr],
         id: ast::DUMMY_NODE_ID,
         node: main,
         vis: ast::Visibility::Public,
         span: sp
-    });
-
-    return main;
+    })
 }
 
 fn mk_test_module(cx: &mut TestCtxt) -> (P, Option>) {
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index 86bfdebe42b..9c1371a31fe 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -10,16 +10,16 @@
 
 //! # Token Streams
 //!
-//! TokenStreams represent syntactic objects before they are converted into ASTs.
+//! `TokenStream`s represent syntactic objects before they are converted into ASTs.
 //! A `TokenStream` is, roughly speaking, a sequence (eg stream) of `TokenTree`s,
 //! which are themselves a single `Token` or a `Delimited` subsequence of tokens.
 //!
 //! ## Ownership
-//! TokenStreams are persistent data structures constructed as ropes with reference
-//! counted-children. In general, this means that calling an operation on a TokenStream
-//! (such as `slice`) produces an entirely new TokenStream from the borrowed reference to
-//! the original. This essentially coerces TokenStreams into 'views' of their subparts,
-//! and a borrowed TokenStream is sufficient to build an owned TokenStream without taking
+//! `TokenStreams` are persistent data structures constructed as ropes with reference
+//! counted-children. In general, this means that calling an operation on a `TokenStream`
+//! (such as `slice`) produces an entirely new `TokenStream` from the borrowed reference to
+//! the original. This essentially coerces `TokenStream`s into 'views' of their subparts,
+//! and a borrowed `TokenStream` is sufficient to build an owned `TokenStream` without taking
 //! ownership of the original.
 
 use syntax_pos::{BytePos, Span, DUMMY_SP};
@@ -88,7 +88,7 @@ impl Delimited {
 /// If the syntax extension is an MBE macro, it will attempt to match its
 /// LHS token tree against the provided token tree, and if it finds a
 /// match, will transcribe the RHS token tree, splicing in any captured
-/// macro_parser::matched_nonterminals into the `SubstNt`s it finds.
+/// `macro_parser::matched_nonterminals` into the `SubstNt`s it finds.
 ///
 /// The RHS of an MBE macro is the only place `SubstNt`s are substituted.
 /// Nothing special happens to misnamed or misplaced `SubstNt`s.
diff --git a/src/libsyntax/util/lev_distance.rs b/src/libsyntax/util/lev_distance.rs
index a6fff2d7074..9307f3c58d4 100644
--- a/src/libsyntax/util/lev_distance.rs
+++ b/src/libsyntax/util/lev_distance.rs
@@ -53,9 +53,10 @@ pub fn find_best_match_for_name<'a, T>(iter_names: T,
     iter_names
     .filter_map(|&name| {
         let dist = lev_distance(lookup, &name.as_str());
-        match dist <= max_dist {    // filter the unwanted cases
-            true => Some((name, dist)),
-            false => None,
+        if dist <= max_dist {    // filter the unwanted cases
+            Some((name, dist))
+        } else {
+            None
         }
     })
     .min_by_key(|&(_, val)| val)    // extract the tuple containing the minimum edit distance
diff --git a/src/libsyntax/util/move_map.rs b/src/libsyntax/util/move_map.rs
index fe05e2958b3..8cc37afa354 100644
--- a/src/libsyntax/util/move_map.rs
+++ b/src/libsyntax/util/move_map.rs
@@ -37,10 +37,10 @@ impl MoveMap for Vec {
                 // move the read_i'th item out of the vector and map it
                 // to an iterator
                 let e = ptr::read(self.get_unchecked(read_i));
-                let mut iter = f(e).into_iter();
+                let iter = f(e).into_iter();
                 read_i += 1;
 
-                while let Some(e) = iter.next() {
+                for e in iter {
                     if write_i < read_i {
                         ptr::write(self.get_unchecked_mut(write_i), e);
                         write_i += 1;
@@ -93,10 +93,10 @@ impl MoveMap for SmallVector {
                 // move the read_i'th item out of the vector and map it
                 // to an iterator
                 let e = ptr::read(self.get_unchecked(read_i));
-                let mut iter = f(e).into_iter();
+                let iter = f(e).into_iter();
                 read_i += 1;
 
-                while let Some(e) = iter.next() {
+                for e in iter {
                     if write_i < read_i {
                         ptr::write(self.get_unchecked_mut(write_i), e);
                         write_i += 1;
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 2e42c6986e6..6e613d1eee7 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -343,9 +343,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
             visitor.visit_ty(ty);
             visitor.visit_expr(expression)
         }
-        TyKind::TraitObject(ref bounds) => {
-            walk_list!(visitor, visit_ty_param_bound, bounds);
-        }
+        TyKind::TraitObject(ref bounds) |
         TyKind::ImplTrait(ref bounds) => {
             walk_list!(visitor, visit_ty_param_bound, bounds);
         }
@@ -540,7 +538,7 @@ pub fn walk_fn<'a, V>(visitor: &mut V, kind: FnKind<'a>, declaration: &'a FnDecl
             walk_fn_decl(visitor, declaration);
             visitor.visit_block(body);
         }
-        FnKind::Method(_, ref sig, _, body) => {
+        FnKind::Method(_, sig, _, body) => {
             visitor.visit_generics(&sig.generics);
             walk_fn_decl(visitor, declaration);
             visitor.visit_block(body);
@@ -776,7 +774,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
         }
         ExprKind::InlineAsm(ref ia) => {
             for &(_, ref input) in &ia.inputs {
-                visitor.visit_expr(&input)
+                visitor.visit_expr(input)
             }
             for output in &ia.outputs {
                 visitor.visit_expr(&output.expr)
-- 
cgit 1.4.1-3-g733a5


From 958c67d9c8ca74370e2052fd8a3d209b8184d1f4 Mon Sep 17 00:00:00 2001
From: Andre Bogus 
Date: Sat, 13 May 2017 21:40:06 +0200
Subject: adressed comments by @kennytm and @petrochenkov

---
 src/libsyntax/diagnostics/plugin.rs  |  4 +--
 src/libsyntax/ext/base.rs            |  4 +--
 src/libsyntax/ext/tt/macro_parser.rs | 50 +++++++++++++++++++-----------------
 src/libsyntax/ext/tt/macro_rules.rs  |  3 ++-
 src/libsyntax/feature_gate.rs        |  7 +++--
 src/libsyntax/parse/classify.rs      |  2 +-
 src/libsyntax/parse/mod.rs           |  1 -
 src/libsyntax/parse/parser.rs        |  6 ++---
 src/libsyntax/print/pprust.rs        |  2 +-
 9 files changed, 41 insertions(+), 38 deletions(-)

(limited to 'src/libsyntax/parse')

diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs
index ca89a80fdee..73aeb40df84 100644
--- a/src/libsyntax/diagnostics/plugin.rs
+++ b/src/libsyntax/diagnostics/plugin.rs
@@ -111,7 +111,7 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt,
     // overflow the maximum line width.
     description.map(|raw_msg| {
         let msg = raw_msg.as_str();
-        if !msg.starts_with('\n') || !msg.ends_with('\n') {
+        if !msg.starts_with("\n") || !msg.ends_with("\n") {
             ecx.span_err(span, &format!(
                 "description for error code {} doesn't start and end with a newline",
                 code
@@ -120,7 +120,7 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt,
 
         // URLs can be unavoidably longer than the line limit, so we allow them.
         // Allowed format is: `[name]: https://www.rust-lang.org/`
-        let is_url = |l: &str| l.starts_with('[') && l.contains("]:") && l.contains("http");
+        let is_url = |l: &str| l.starts_with("[") && l.contains("]:") && l.contains("http");
 
         if msg.lines().any(|line| line.len() > MAX_DESCRIPTION_WIDTH && !is_url(line)) {
             ecx.span_err(span, &format!(
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index f78089aaa75..31a7e0d58d0 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -635,8 +635,8 @@ pub struct ExpansionData {
 }
 
 /// One of these is made during expansion and incrementally updated as we go;
-/// when a macro expansion occurs, the resulting nodes have the backtrace()
-/// -> `expn_info` of their expansion context stored into their span.
+/// when a macro expansion occurs, the resulting nodes have the `backtrace()
+/// -> expn_info` of their expansion context stored into their span.
 pub struct ExtCtxt<'a> {
     pub parse_sess: &'a parse::ParseSess,
     pub ecfg: expand::ExpansionConfig<'a>,
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index 8e28135b11d..a0103a1e3fe 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -36,43 +36,47 @@
 //! repetitions indicated by Kleene stars. It only advances or calls out to the
 //! real Rust parser when no `cur_eis` items remain
 //!
-//! Example: Start parsing `a a a a b` against [· a $( a )* a b].
+//! Example:
 //!
-//! Remaining input: `a a a a b`
-//! `next_eis`: `[· a $( a )* a b]`
+//! ```text, ignore
+//! Start parsing a a a a b against [· a $( a )* a b].
 //!
-//! - - - Advance over an `a`. - - -
+//! Remaining input: a a a a b
+//! next_eis: [· a $( a )* a b]
 //!
-//! Remaining input: `a a a b`
-//! cur: `[a · $( a )* a b]`
+//! - - - Advance over an a. - - -
+//!
+//! Remaining input: a a a b
+//! cur: [a · $( a )* a b]
 //! Descend/Skip (first item).
-//! next: `[a $( · a )* a b]  [a $( a )* · a b]`.
+//! next: [a $( · a )* a b]  [a $( a )* · a b].
 //!
-//! - - - Advance over an `a`. - - -
+//! - - - Advance over an a. - - -
 //!
-//! Remaining input: `a a b`
-//! cur: `[a $( a · )* a b]`  next: `[a $( a )* a · b]`
+//! Remaining input: a a b
+//! cur: [a $( a · )* a b]  next: [a $( a )* a · b]
 //! Finish/Repeat (first item)
-//! next: `[a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]`
+//! next: [a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]
 //!
-//! - - - Advance over an `a`. - - - (this looks exactly like the last step)
+//! - - - Advance over an a. - - - (this looks exactly like the last step)
 //!
-//! Remaining input: `a b`
-//! cur: `[a $( a · )* a b]`  next: `[a $( a )* a · b]`
+//! Remaining input: a b
+//! cur: [a $( a · )* a b]  next: [a $( a )* a · b]
 //! Finish/Repeat (first item)
-//! next: `[a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]`
+//! next: [a $( a )* · a b]  [a $( · a )* a b]  [a $( a )* a · b]
 //!
-//! - - - Advance over an `a`. - - - (this looks exactly like the last step)
+//! - - - Advance over an a. - - - (this looks exactly like the last step)
 //!
-//! Remaining input: `b`
-//! cur: `[a $( a · )* a b]`  next: `[a $( a )* a · b]`
+//! Remaining input: b
+//! cur: [a $( a · )* a b]  next: [a $( a )* a · b]
 //! Finish/Repeat (first item)
-//! next: `[a $( a )* · a b]  [a $( · a )* a b]`
+//! next: [a $( a )* · a b]  [a $( · a )* a b]
 //!
-//! - - - Advance over a `b`. - - -
+//! - - - Advance over a b. - - -
 //!
-//! Remaining input: ``
-//! eof: `[a $( a )* a b ·]`
+//! Remaining input: ''
+//! eof: [a $( a )* a b ·]
+//! ```
 
 pub use self::NamedMatch::*;
 pub use self::ParseResult::*;
@@ -485,7 +489,7 @@ pub fn parse(sess: &ParseSess, tts: TokenStream, ms: &[TokenTree], directory: Op
 }
 
 fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
-    if let "tt" = name {
+    if name == "tt" {
         return token::NtTT(p.parse_token_tree());
     }
     // check at the beginning and the parser checks after each bump
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 9e3fe30e7bf..4a307ab18a5 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -858,6 +858,7 @@ fn quoted_tt_to_string(tt: "ed::TokenTree) -> String {
     match *tt {
         quoted::TokenTree::Token(_, ref tok) => ::print::pprust::token_to_string(tok),
         quoted::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind),
-        _ => panic!("unexpected quoted::TokenTree::{{Sequence or Delimited}} in follow set checker"),
+        _ => panic!("unexpected quoted::TokenTree::{{Sequence or Delimited}} \
+                     in follow set checker"),
     }
 }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index f95693f6820..09090ab8731 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -1216,7 +1216,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             }
 
             ast::ItemKind::Impl(_, polarity, defaultness, _, _, _, _) => {
-                if let ast::ImplPolarity::Negative = polarity {
+                if polarity == ast::ImplPolarity::Negative {
                     gate_feature_post!(&self, optin_builtin_traits,
                                        i.span,
                                        "negative trait bounds are not yet fully implemented; \
@@ -1269,10 +1269,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
 
     fn visit_fn_ret_ty(&mut self, ret_ty: &'a ast::FunctionRetTy) {
         if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
-            if let ast::TyKind::Never = output_ty.node {
-                return
+            if output_ty.node != ast::TyKind::Never {
+                self.visit_ty(output_ty)
             }
-            self.visit_ty(output_ty)
         }
     }
 
diff --git a/src/libsyntax/parse/classify.rs b/src/libsyntax/parse/classify.rs
index c2755cf0591..0c6f09ba766 100644
--- a/src/libsyntax/parse/classify.rs
+++ b/src/libsyntax/parse/classify.rs
@@ -48,8 +48,8 @@ pub fn expr_is_simple_block(e: &ast::Expr) -> bool {
 pub fn stmt_ends_with_semi(stmt: &ast::StmtKind) -> bool {
     match *stmt {
         ast::StmtKind::Local(_) => true,
-        ast::StmtKind::Item(_) => false,
         ast::StmtKind::Expr(ref e) => expr_requires_semi_to_be_stmt(e),
+        ast::StmtKind::Item(_) |
         ast::StmtKind::Semi(..) |
         ast::StmtKind::Mac(..) => false,
     }
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 4fcf7614622..1eff819d755 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -341,7 +341,6 @@ pub fn raw_str_lit(lit: &str) -> String {
     debug!("raw_str_lit: given {}", escape_default(lit));
     let mut res = String::with_capacity(lit.len());
 
-    // FIXME #8372: This could be a for-loop if it didn't borrow the iterator
     let mut chars = lit.chars().peekable();
     while let Some(c) = chars.next() {
         if c == '\r' {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 28c57e0855f..4741f896d3c 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1546,7 +1546,7 @@ impl<'a> Parser<'a> {
     pub fn is_named_argument(&mut self) -> bool {
         let offset = match self.token {
             token::BinOp(token::And) |
-            token::AndAnd |
+            token::AndAnd => 1,
             _ if self.token.is_keyword(keywords::Mut) => 1,
             _ => 0
         };
@@ -2569,7 +2569,7 @@ impl<'a> Parser<'a> {
                             s.print_usize(float.trunc() as usize)?;
                             s.pclose()?;
                             word(&mut s.s, ".")?;
-                            word(&mut s.s, fstr.splitn(2, '.').last().unwrap())
+                            word(&mut s.s, fstr.splitn(2, ".").last().unwrap())
                         });
                         err.span_suggestion(
                             lo.to(self.prev_span),
@@ -4917,7 +4917,7 @@ impl<'a> Parser<'a> {
                 }
             }
         } else {
-            if let ast::ImplPolarity::Negative = polarity {
+            if polarity == ast::ImplPolarity::Negative {
                 // This is a negated type implementation
                 // `impl !MyType {}`, which is not allowed.
                 self.span_err(neg_span, "inherent implementation can't be negated");
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 6114db25fe8..bdb4ce34b91 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1327,7 +1327,7 @@ impl<'a> State<'a> {
                     space(&mut self.s)?;
                 }
 
-                if let ast::ImplPolarity::Negative = polarity {
+                if polarity == ast::ImplPolarity::Negative {
                     word(&mut self.s, "!")?;
                 }
 
-- 
cgit 1.4.1-3-g733a5


From a2566301e12364e227f0b72b51bb09698e1cb9dc Mon Sep 17 00:00:00 2001
From: Nick Cameron 
Date: Thu, 18 May 2017 10:37:24 +1200
Subject: Add an option to the parser to avoid parsing out of line modules

This is useful if parsing from stdin or a String and don't want to try and read in a module from another file. Instead we just leave a stub in the AST.
---
 src/libsyntax/attr.rs                |  2 +-
 src/libsyntax/ext/tt/macro_parser.rs |  8 ++++++--
 src/libsyntax/ext/tt/macro_rules.rs  |  4 ++--
 src/libsyntax/parse/mod.rs           | 25 +++++++++++++++++++++++--
 src/libsyntax/parse/parser.rs        | 15 +++++++++++++--
 src/libsyntax/tokenstream.rs         |  2 +-
 6 files changed, 46 insertions(+), 10 deletions(-)

(limited to 'src/libsyntax/parse')

diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 45f891d8dc5..8e63e219c42 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -320,7 +320,7 @@ impl Attribute {
     pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T>
         where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
     {
-        let mut parser = Parser::new(sess, self.tokens.clone(), None, false);
+        let mut parser = Parser::new(sess, self.tokens.clone(), None, false, false);
         let result = f(&mut parser)?;
         if parser.token != token::Eof {
             parser.unexpected()?;
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index bf66aa0f00b..0b6a2eb536a 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -418,9 +418,13 @@ fn inner_parse_loop(sess: &ParseSess,
     Success(())
 }
 
-pub fn parse(sess: &ParseSess, tts: TokenStream, ms: &[TokenTree], directory: Option)
+pub fn parse(sess: &ParseSess,
+             tts: TokenStream,
+             ms: &[TokenTree],
+             directory: Option,
+             recurse_into_modules: bool)
              -> NamedParseResult {
-    let mut parser = Parser::new(sess, tts, directory, true);
+    let mut parser = Parser::new(sess, tts, directory, recurse_into_modules, true);
     let mut cur_eis = SmallVector::one(initial_matcher_pos(ms.to_owned(), parser.span.lo));
     let mut next_eis = Vec::new(); // or proceed normally
 
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index a208f530602..73494d47fee 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -121,7 +121,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
                     path: cx.current_expansion.module.directory.clone(),
                     ownership: cx.current_expansion.directory_ownership,
                 };
-                let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), false);
+                let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), true, false);
                 p.root_module_name = cx.current_expansion.module.mod_path.last()
                     .map(|id| id.name.as_str().to_string());
 
@@ -192,7 +192,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item)
         ast::ItemKind::MacroDef(ref body) => body.clone().into(),
         _ => unreachable!(),
     };
-    let argument_map = match parse(sess, body, &argument_gram, None) {
+    let argument_map = match parse(sess, body, &argument_gram, None, true) {
         Success(m) => m,
         Failure(sp, tok) => {
             let s = parse_failure_msg(tok);
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 1eff819d755..3a68a6ba764 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -149,7 +149,9 @@ pub fn parse_stream_from_source_str(name: String, source: String, sess: &ParseSe
 // Create a new parser from a source string
 pub fn new_parser_from_source_str(sess: &ParseSess, name: String, source: String)
                                       -> Parser {
-    filemap_to_parser(sess, sess.codemap().new_filemap(name, source))
+    let mut parser = filemap_to_parser(sess, sess.codemap().new_filemap(name, source));
+    parser.recurse_into_file_modules = false;
+    parser
 }
 
 /// Create a new parser, handling errors as appropriate
@@ -218,7 +220,7 @@ pub fn filemap_to_stream(sess: &ParseSess, filemap: Rc) -> TokenStream
 
 /// Given stream and the `ParseSess`, produce a parser
 pub fn stream_to_parser(sess: &ParseSess, stream: TokenStream) -> Parser {
-    Parser::new(sess, stream, None, false)
+    Parser::new(sess, stream, None, true, false)
 }
 
 /// Parse a string representing a character literal into its final form.
@@ -1032,4 +1034,23 @@ mod tests {
             Err(_) => panic!("could not get snippet"),
         }
     }
+
+    // This tests that when parsing a string (rather than a file) we don't try
+    // and read in a file for a module declaration and just parse a stub.
+    // See `recurse_into_file_modules` in the parser.
+    #[test]
+    fn out_of_line_mod() {
+        let sess = ParseSess::new(FilePathMapping::empty());
+        let item = parse_item_from_source_str(
+            "foo".to_owned(),
+            "mod foo { struct S; mod this_does_not_exist; }".to_owned(),
+            &sess,
+        ).unwrap().unwrap();
+
+        if let ast::ItemKind::Mod(ref m) = item.node {
+            assert!(m.items.len() == 2);
+        } else {
+            panic!();
+        }
+    }
 }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 4741f896d3c..c28f678cb51 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -179,6 +179,8 @@ pub struct Parser<'a> {
     pub obsolete_set: HashSet,
     /// Used to determine the path to externally loaded source files
     pub directory: Directory,
+    /// Whether to parse sub-modules in other files.
+    pub recurse_into_file_modules: bool,
     /// Name of the root module this parser originated from. If `None`, then the
     /// name is not known. This does not change while the parser is descending
     /// into modules, and sub-parsers have new values for this name.
@@ -190,6 +192,7 @@ pub struct Parser<'a> {
     pub cfg_mods: bool,
 }
 
+
 struct TokenCursor {
     frame: TokenCursorFrame,
     stack: Vec,
@@ -439,6 +442,7 @@ impl<'a> Parser<'a> {
     pub fn new(sess: &'a ParseSess,
                tokens: TokenStream,
                directory: Option,
+               recurse_into_file_modules: bool,
                desugar_doc_comments: bool)
                -> Self {
         let mut parser = Parser {
@@ -450,6 +454,7 @@ impl<'a> Parser<'a> {
             prev_token_kind: PrevTokenKind::Other,
             restrictions: Restrictions::empty(),
             obsolete_set: HashSet::new(),
+            recurse_into_file_modules: recurse_into_file_modules,
             directory: Directory { path: PathBuf::new(), ownership: DirectoryOwnership::Owned },
             root_module_name: None,
             expected_tokens: Vec::new(),
@@ -467,12 +472,14 @@ impl<'a> Parser<'a> {
         let tok = parser.next_tok();
         parser.token = tok.tok;
         parser.span = tok.sp;
+
         if let Some(directory) = directory {
             parser.directory = directory;
         } else if parser.span != syntax_pos::DUMMY_SP {
             parser.directory.path = PathBuf::from(sess.codemap().span_to_filename(parser.span));
             parser.directory.path.pop();
         }
+
         parser.process_potential_macro_variable();
         parser
     }
@@ -3921,6 +3928,7 @@ impl<'a> Parser<'a> {
                 mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock);
             let item = self.parse_item_(attrs.clone(), false, true)?;
             self.directory.ownership = old_directory_ownership;
+
             match item {
                 Some(i) => Stmt {
                     id: ast::DUMMY_NODE_ID,
@@ -5254,7 +5262,7 @@ impl<'a> Parser<'a> {
         let id = self.parse_ident()?;
         if self.check(&token::Semi) {
             self.bump();
-            if in_cfg {
+            if in_cfg && self.recurse_into_file_modules {
                 // This mod is in an external file. Let's go get it!
                 let ModulePathSuccess { path, directory_ownership, warn } =
                     self.submod_path(id, &outer_attrs, id_span)?;
@@ -5281,10 +5289,12 @@ impl<'a> Parser<'a> {
         } else {
             let old_directory = self.directory.clone();
             self.push_directory(id, &outer_attrs);
+
             self.expect(&token::OpenDelim(token::Brace))?;
             let mod_inner_lo = self.span;
             let attrs = self.parse_inner_attributes()?;
             let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?;
+
             self.directory = old_directory;
             Ok((id, ItemKind::Mod(module), Some(attrs)))
         }
@@ -5347,7 +5357,8 @@ impl<'a> Parser<'a> {
     fn submod_path(&mut self,
                    id: ast::Ident,
                    outer_attrs: &[ast::Attribute],
-                   id_sp: Span) -> PResult<'a, ModulePathSuccess> {
+                   id_sp: Span)
+                   -> PResult<'a, ModulePathSuccess> {
         if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) {
             return Ok(ModulePathSuccess {
                 directory_ownership: match path.file_name().and_then(|s| s.to_str()) {
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index 9c1371a31fe..339e7c0b628 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -109,7 +109,7 @@ impl TokenTree {
             path: cx.current_expansion.module.directory.clone(),
             ownership: cx.current_expansion.directory_ownership,
         };
-        macro_parser::parse(cx.parse_sess(), tts, mtch, Some(directory))
+        macro_parser::parse(cx.parse_sess(), tts, mtch, Some(directory), true)
     }
 
     /// Check if this TokenTree is equal to the other, regardless of span information.
-- 
cgit 1.4.1-3-g733a5


From 9ad0dbab5b134592141efdcc93d37ea6a65e425f Mon Sep 17 00:00:00 2001
From: Andy Russell 
Date: Sat, 20 May 2017 11:18:26 -0400
Subject: remove "much" from unicode diagnostic

---
 src/libsyntax/parse/lexer/unicode_chars.rs | 2 +-
 src/test/parse-fail/unicode-chars.rs       | 3 +--
 2 files changed, 2 insertions(+), 3 deletions(-)

(limited to 'src/libsyntax/parse')

diff --git a/src/libsyntax/parse/lexer/unicode_chars.rs b/src/libsyntax/parse/lexer/unicode_chars.rs
index 4df23da3c9c..83a164bdb96 100644
--- a/src/libsyntax/parse/lexer/unicode_chars.rs
+++ b/src/libsyntax/parse/lexer/unicode_chars.rs
@@ -238,7 +238,7 @@ pub fn check_for_substitution<'a>(reader: &StringReader<'a>,
         match ASCII_ARRAY.iter().find(|&&(c, _)| c == ascii_char) {
             Some(&(ascii_char, ascii_name)) => {
                 let msg =
-                    format!("unicode character '{}' ({}) looks much like '{}' ({}), but it's not",
+                    format!("unicode character '{}' ({}) looks like '{}' ({}), but it's not",
                             ch, u_name, ascii_char, ascii_name);
                 err.span_help(span, &msg);
             },
diff --git a/src/test/parse-fail/unicode-chars.rs b/src/test/parse-fail/unicode-chars.rs
index adfaf62b5d3..1bdeb121a55 100644
--- a/src/test/parse-fail/unicode-chars.rs
+++ b/src/test/parse-fail/unicode-chars.rs
@@ -9,10 +9,9 @@
 // except according to those terms.
 
 // compile-flags: -Z parse-only
-// ignore-tidy-linelength
 
 fn main() {
     let y = 0;
     //~^ ERROR unknown start of token: \u{37e}
-    //~^^ HELP unicode character ';' (Greek Question Mark) looks much like ';' (Semicolon), but it's not
+    //~^^ HELP unicode character ';' (Greek Question Mark) looks like ';' (Semicolon), but it's not
 }
-- 
cgit 1.4.1-3-g733a5


From 9c6430b3257a96d587349d85aa7596d3f4704c28 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Fri, 17 Mar 2017 21:58:48 +0000
Subject: Refactor out `ast::MacroDef`.

---
 src/librustc/hir/lowering.rs         |  2 +-
 src/librustc/lint/context.rs         |  3 +--
 src/librustc_metadata/cstore_impl.rs |  4 +++-
 src/librustdoc/visit_ast.rs          |  5 ++---
 src/libsyntax/ast.rs                 | 13 ++++++++++++-
 src/libsyntax/ext/tt/macro_rules.rs  |  2 +-
 src/libsyntax/fold.rs                | 12 +++++++++++-
 src/libsyntax/parse/parser.rs        |  4 +++-
 src/libsyntax/print/pprust.rs        |  2 +-
 src/libsyntax/visit.rs               |  3 +--
 10 files changed, 36 insertions(+), 14 deletions(-)

(limited to 'src/libsyntax/parse')

diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index d359c69d3a0..77bcde22ef7 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1505,7 +1505,7 @@ impl<'a> LoweringContext<'a> {
         if let ItemKind::MacroDef(ref tts) = i.node {
             if i.attrs.iter().any(|attr| attr.path == "macro_export") {
                 self.exported_macros.push(hir::MacroDef {
-                    name: name, attrs: attrs, id: i.id, span: i.span, body: tts.clone().into(),
+                    name: name, attrs: attrs, id: i.id, span: i.span, body: tts.stream(),
                 });
             }
             return None;
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 9d5ba2c8f95..a265a84114a 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -49,7 +49,6 @@ use hir;
 use hir::def_id::LOCAL_CRATE;
 use hir::intravisit as hir_visit;
 use syntax::visit as ast_visit;
-use syntax::tokenstream::ThinTokenStream;
 
 /// Information about the registered lints.
 ///
@@ -1127,7 +1126,7 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> {
         run_lints!(self, check_attribute, early_passes, attr);
     }
 
-    fn visit_mac_def(&mut self, _mac: &'a ThinTokenStream, id: ast::NodeId) {
+    fn visit_mac_def(&mut self, _mac: &'a ast::MacroDef, id: ast::NodeId) {
         let lints = self.sess.lints.borrow_mut().take(id);
         for early_lint in lints {
             self.early_lint(&early_lint);
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 7478f902e06..06472ed7fd1 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -386,7 +386,9 @@ impl CrateStore for cstore::CStore {
             id: ast::DUMMY_NODE_ID,
             span: local_span,
             attrs: attrs.iter().cloned().collect(),
-            node: ast::ItemKind::MacroDef(body.into()),
+            node: ast::ItemKind::MacroDef(ast::MacroDef {
+                tokens: body.into(),
+            }),
             vis: ast::Visibility::Inherited,
         })
     }
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index d463e41c58a..39ebe490d0e 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -16,7 +16,6 @@ use std::mem;
 use syntax::abi;
 use syntax::ast;
 use syntax::attr;
-use syntax::tokenstream::TokenStream;
 use syntax_pos::Span;
 
 use rustc::hir::map as hir_map;
@@ -214,8 +213,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                         LoadedMacro::ProcMacro(..) => continue,
                     };
 
-                    let matchers = if let ast::ItemKind::MacroDef(ref tokens) = def.node {
-                        let tts: Vec<_> = TokenStream::from(tokens.clone()).into_trees().collect();
+                    let matchers = if let ast::ItemKind::MacroDef(ref def) = def.node {
+                        let tts: Vec<_> = def.stream().into_trees().collect();
                         tts.chunks(4).map(|arm| arm[0].span()).collect()
                     } else {
                         unreachable!()
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 24ce99208ed..6a30072c835 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1019,6 +1019,17 @@ impl Mac_ {
     }
 }
 
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct MacroDef {
+    pub tokens: ThinTokenStream,
+}
+
+impl MacroDef {
+    pub fn stream(&self) -> TokenStream {
+        self.tokens.clone().into()
+    }
+}
+
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
 pub enum StrStyle {
     /// A regular string, like `"foo"`
@@ -1863,7 +1874,7 @@ pub enum ItemKind {
     Mac(Mac),
 
     /// A macro definition.
-    MacroDef(ThinTokenStream),
+    MacroDef(MacroDef),
 }
 
 impl ItemKind {
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 73494d47fee..7ac3990def4 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -189,7 +189,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item)
 
     // Parse the macro_rules! invocation
     let body = match def.node {
-        ast::ItemKind::MacroDef(ref body) => body.clone().into(),
+        ast::ItemKind::MacroDef(ref body) => body.stream(),
         _ => unreachable!(),
     };
     let argument_map = match parse(sess, body, &argument_gram, None, true) {
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 58cf50cdc00..9aeb9ecca5a 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -189,6 +189,10 @@ pub trait Folder : Sized {
         // fold::noop_fold_mac(_mac, self)
     }
 
+    fn fold_macro_def(&mut self, def: MacroDef) -> MacroDef {
+        noop_fold_macro_def(def, self)
+    }
+
     fn fold_lifetime(&mut self, l: Lifetime) -> Lifetime {
         noop_fold_lifetime(l, self)
     }
@@ -515,6 +519,12 @@ pub fn noop_fold_mac(Spanned {node, span}: Mac, fld: &mut T) -> Mac {
     }
 }
 
+pub fn noop_fold_macro_def(def: MacroDef, fld: &mut T) -> MacroDef {
+    MacroDef {
+        tokens: fld.fold_tts(def.tokens.into()).into(),
+    }
+}
+
 pub fn noop_fold_meta_list_item(li: NestedMetaItem, fld: &mut T)
     -> NestedMetaItem {
     Spanned {
@@ -919,7 +929,7 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind {
             items.move_flat_map(|item| folder.fold_trait_item(item)),
         ),
         ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)),
-        ItemKind::MacroDef(tts) => ItemKind::MacroDef(folder.fold_tts(tts.into()).into()),
+        ItemKind::MacroDef(def) => ItemKind::MacroDef(folder.fold_macro_def(def)),
     }
 }
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index c28f678cb51..3c9ad8ca9c0 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -3781,7 +3781,9 @@ impl<'a> Parser<'a> {
         }
 
         let span = lo.to(self.prev_span);
-        let kind = ItemKind::MacroDef(tts);
+        let kind = ItemKind::MacroDef(ast::MacroDef {
+            tokens: tts,
+        });
         Ok(Some(self.mk_item(span, id, kind, Visibility::Inherited, attrs.to_owned())))
     }
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 83c289ff80b..6c5bf56070e 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1392,7 +1392,7 @@ impl<'a> State<'a> {
                 self.print_ident(item.ident)?;
                 self.cbox(INDENT_UNIT)?;
                 self.popen()?;
-                self.print_tts(tts.clone().into())?;
+                self.print_tts(tts.stream())?;
                 self.pclose()?;
                 word(&mut self.s, ";")?;
                 self.end()?;
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 0fa0753b22c..d29d2497afe 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -27,7 +27,6 @@ use abi::Abi;
 use ast::*;
 use syntax_pos::Span;
 use codemap::Spanned;
-use tokenstream::ThinTokenStream;
 
 #[derive(Copy, Clone, PartialEq, Eq)]
 pub enum FnKind<'a> {
@@ -113,7 +112,7 @@ pub trait Visitor<'ast>: Sized {
         // definition in your trait impl:
         // visit::walk_mac(self, _mac)
     }
-    fn visit_mac_def(&mut self, _mac: &'ast ThinTokenStream, _id: NodeId) {
+    fn visit_mac_def(&mut self, _mac: &'ast MacroDef, _id: NodeId) {
         // Nothing to do
     }
     fn visit_path(&mut self, path: &'ast Path, _id: NodeId) {
-- 
cgit 1.4.1-3-g733a5


From 2a1d2edb821e123586049f349bb4aaee2d001cc6 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Sat, 18 Mar 2017 01:55:51 +0000
Subject: Declarative macros 2.0 without hygiene.

---
 .../src/language-features/decl-macro.md            | 10 ++++
 src/librustc/hir/lowering.rs                       |  7 ++-
 src/librustc/hir/mod.rs                            |  1 +
 src/librustc/ich/impls_hir.rs                      |  1 +
 src/librustc_metadata/cstore_impl.rs               |  1 +
 src/librustc_resolve/build_reduced_graph.rs        |  4 +-
 src/librustc_resolve/lib.rs                        | 12 +++-
 src/librustc_resolve/macros.rs                     | 29 ++++++---
 src/librustc_resolve/resolve_imports.rs            |  2 +-
 src/libsyntax/ast.rs                               |  1 +
 src/libsyntax/ext/tt/macro_rules.rs                | 15 ++---
 src/libsyntax/feature_gate.rs                      | 10 +++-
 src/libsyntax/fold.rs                              |  1 +
 src/libsyntax/parse/parser.rs                      | 68 +++++++++++++++-------
 14 files changed, 116 insertions(+), 46 deletions(-)
 create mode 100644 src/doc/unstable-book/src/language-features/decl-macro.md

(limited to 'src/libsyntax/parse')

diff --git a/src/doc/unstable-book/src/language-features/decl-macro.md b/src/doc/unstable-book/src/language-features/decl-macro.md
new file mode 100644
index 00000000000..4700b252e2d
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/decl-macro.md
@@ -0,0 +1,10 @@
+# `decl_macro`
+
+The tracking issue for this feature is: [#39412]
+
+[#39412]: https://github.com/rust-lang/rust/issues/39412
+
+------------------------
+
+
+
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 77bcde22ef7..5ec8dd0156a 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1502,10 +1502,11 @@ impl<'a> LoweringContext<'a> {
     pub fn lower_item(&mut self, i: &Item) -> Option {
         let mut name = i.ident.name;
         let attrs = self.lower_attrs(&i.attrs);
-        if let ItemKind::MacroDef(ref tts) = i.node {
-            if i.attrs.iter().any(|attr| attr.path == "macro_export") {
+        if let ItemKind::MacroDef(ref def) = i.node {
+            if !def.legacy || i.attrs.iter().any(|attr| attr.path == "macro_export") {
+                let (body, legacy) = (def.stream(), def.legacy);
                 self.exported_macros.push(hir::MacroDef {
-                    name: name, attrs: attrs, id: i.id, span: i.span, body: tts.stream(),
+                    name: name, attrs: attrs, id: i.id, span: i.span, body: body, legacy: legacy,
                 });
             }
             return None;
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index cb7f530b995..6c355608f13 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -536,6 +536,7 @@ pub struct MacroDef {
     pub id: NodeId,
     pub span: Span,
     pub body: TokenStream,
+    pub legacy: bool,
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index abc51601b6e..f9758ceea1e 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -332,6 +332,7 @@ impl_stable_hash_for!(struct hir::MacroDef {
     attrs,
     id,
     span,
+    legacy,
     body
 });
 
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 06472ed7fd1..4e16c97ca4d 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -388,6 +388,7 @@ impl CrateStore for cstore::CStore {
             attrs: attrs.iter().cloned().collect(),
             node: ast::ItemKind::MacroDef(ast::MacroDef {
                 tokens: body.into(),
+                legacy: true,
             }),
             vis: ast::Visibility::Inherited,
         })
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 57639a1ecef..b7b75f8af73 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -77,7 +77,7 @@ struct LegacyMacroImports {
 impl<'a> Resolver<'a> {
     /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
     /// otherwise, reports an error.
-    fn define(&mut self, parent: Module<'a>, ident: Ident, ns: Namespace, def: T)
+    pub fn define(&mut self, parent: Module<'a>, ident: Ident, ns: Namespace, def: T)
         where T: ToNameBinding<'a>,
     {
         let binding = def.to_name_binding(self.arenas);
@@ -730,7 +730,7 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> {
     fn visit_item(&mut self, item: &'a Item) {
         let macro_use = match item.node {
             ItemKind::MacroDef(..) => {
-                self.resolver.define_macro(item, &mut self.legacy_scope);
+                self.resolver.define_macro(item, self.expansion, &mut self.legacy_scope);
                 return
             }
             ItemKind::Mac(..) => {
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 6ea666e21dc..500277e78e6 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -1058,6 +1058,13 @@ impl<'a> NameBinding<'a> {
             _ => true,
         }
     }
+
+    fn is_macro_def(&self) -> bool {
+        match self.kind {
+            NameBindingKind::Def(Def::Macro(..)) => true,
+            _ => false,
+        }
+    }
 }
 
 /// Interns the names of the primitive types.
@@ -1377,8 +1384,9 @@ impl<'a> Resolver<'a> {
                 vis: ty::Visibility::Public,
             }),
 
-            // `#![feature(proc_macro)]` implies `#[feature(extern_macros)]`
-            use_extern_macros: features.use_extern_macros || features.proc_macro,
+            // The `proc_macro` and `decl_macro` features imply `use_extern_macros`
+            use_extern_macros:
+                features.use_extern_macros || features.proc_macro || features.decl_macro,
 
             crate_loader: crate_loader,
             macro_names: FxHashSet(),
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 231d30cd2a2..bf21344330b 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -687,7 +687,10 @@ impl<'a> Resolver<'a> {
         });
     }
 
-    pub fn define_macro(&mut self, item: &ast::Item, legacy_scope: &mut LegacyScope<'a>) {
+    pub fn define_macro(&mut self,
+                        item: &ast::Item,
+                        expansion: Mark,
+                        legacy_scope: &mut LegacyScope<'a>) {
         self.local_macro_def_scopes.insert(item.id, self.current_module);
         let ident = item.ident;
         if ident.name == "macro_rules" {
@@ -699,16 +702,24 @@ impl<'a> Resolver<'a> {
                                                &self.session.features,
                                                item));
         self.macro_map.insert(def_id, ext);
-        *legacy_scope = LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding {
-            parent: Cell::new(*legacy_scope), name: ident.name, def_id: def_id, span: item.span,
-        }));
-        self.macro_names.insert(ident.name);
 
-        if attr::contains_name(&item.attrs, "macro_export") {
-            let def = Def::Macro(def_id, MacroKind::Bang);
-            self.macro_exports.push(Export { name: ident.name, def: def, span: item.span });
+        let def = match item.node { ast::ItemKind::MacroDef(ref def) => def, _ => unreachable!() };
+        if def.legacy {
+            self.macro_names.insert(ident.name);
+            *legacy_scope = LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding {
+                parent: Cell::new(*legacy_scope), name: ident.name, def_id: def_id, span: item.span,
+            }));
+            if attr::contains_name(&item.attrs, "macro_export") {
+                let def = Def::Macro(def_id, MacroKind::Bang);
+                self.macro_exports.push(Export { name: ident.name, def: def, span: item.span });
+            } else {
+                self.unused_macros.insert(def_id);
+            }
         } else {
-            self.unused_macros.insert(def_id);
+            let module = self.current_module;
+            let def = Def::Macro(def_id, MacroKind::Bang);
+            let vis = self.resolve_visibility(&item.vis);
+            self.define(module, ident, MacroNS, (def, vis, item.span, expansion));
         }
     }
 
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 1d4ba4ed100..fdca931ad47 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -803,7 +803,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
             };
 
             if binding.vis == ty::Visibility::Public &&
-               (binding.is_import() || binding.is_extern_crate()) {
+               (binding.is_import() || binding.is_macro_def()) {
                 let def = binding.def();
                 if def != Def::Err {
                     if !def.def_id().is_local() {
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 6a30072c835..3dcb77a0497 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1022,6 +1022,7 @@ impl Mac_ {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct MacroDef {
     pub tokens: ThinTokenStream,
+    pub legacy: bool,
 }
 
 impl MacroDef {
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 7ac3990def4..ad09d583734 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -162,6 +162,12 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item)
     let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs"));
     let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs"));
 
+    // Parse the macro_rules! invocation
+    let body = match def.node {
+        ast::ItemKind::MacroDef(ref body) => body,
+        _ => unreachable!(),
+    };
+
     // The pattern that macro_rules matches.
     // The grammar for macro_rules! is:
     // $( $lhs:tt => $rhs:tt );+
@@ -174,7 +180,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item)
                 quoted::TokenTree::Token(DUMMY_SP, token::FatArrow),
                 quoted::TokenTree::MetaVarDecl(DUMMY_SP, rhs_nm, ast::Ident::from_str("tt")),
             ],
-            separator: Some(token::Semi),
+            separator: Some(if body.legacy { token::Semi } else { token::Comma }),
             op: quoted::KleeneOp::OneOrMore,
             num_captures: 2,
         })),
@@ -187,12 +193,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item)
         })),
     ];
 
-    // Parse the macro_rules! invocation
-    let body = match def.node {
-        ast::ItemKind::MacroDef(ref body) => body.stream(),
-        _ => unreachable!(),
-    };
-    let argument_map = match parse(sess, body, &argument_gram, None, true) {
+    let argument_map = match parse(sess, body.stream(), &argument_gram, None, true) {
         Success(m) => m,
         Failure(sp, tok) => {
             let s = parse_failure_msg(tok);
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index e1b7d4681ad..076639a31ea 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -309,9 +309,12 @@ declare_features! (
     // The `unadjusted` ABI. Perma unstable.
     (active, abi_unadjusted, "1.16.0", None),
 
-    // Macros 1.1
+    // Procedural macros 2.0.
     (active, proc_macro, "1.16.0", Some(38356)),
 
+    // Declarative macros 2.0 (`macro`).
+    (active, decl_macro, "1.17.0", Some(39412)),
+
     // Allows attributes on struct literal fields.
     (active, struct_field_attributes, "1.16.0", Some(38814)),
 
@@ -1229,6 +1232,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 }
             }
 
+            ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => {
+                let msg = "`macro` is experimental";
+                gate_feature_post!(&self, decl_macro, i.span, msg);
+            }
+
             _ => {}
         }
 
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 9aeb9ecca5a..1d1e46cf576 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -522,6 +522,7 @@ pub fn noop_fold_mac(Spanned {node, span}: Mac, fld: &mut T) -> Mac {
 pub fn noop_fold_macro_def(def: MacroDef, fld: &mut T) -> MacroDef {
     MacroDef {
         tokens: fld.fold_tts(def.tokens.into()).into(),
+        legacy: def.legacy,
     }
 }
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 3c9ad8ca9c0..bc9be809ca4 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -3758,33 +3758,59 @@ impl<'a> Parser<'a> {
     fn eat_macro_def(&mut self, attrs: &[Attribute], vis: &Visibility)
                      -> PResult<'a, Option>> {
         let lo = self.span;
-        match self.token {
-            token::Ident(ident) if ident.name == "macro_rules" => {
-                if self.look_ahead(1, |t| *t == token::Not) {
-                    let prev_span = self.prev_span;
-                    self.complain_if_pub_macro(vis, prev_span);
-                    self.bump();
-                    self.bump();
+        let (ident, def) = match self.token {
+            token::Ident(ident) if ident.name == keywords::Macro.name() => {
+                self.bump();
+                let ident = self.parse_ident()?;
+                let tokens = if self.check(&token::OpenDelim(token::Brace)) {
+                    match self.parse_token_tree() {
+                        TokenTree::Delimited(_, ref delimited) => delimited.stream(),
+                        _ => unreachable!(),
+                    }
+                } else if self.check(&token::OpenDelim(token::Paren)) {
+                    let args = self.parse_token_tree();
+                    let body = if self.check(&token::OpenDelim(token::Brace)) {
+                        self.parse_token_tree()
+                    } else {
+                        self.unexpected()?;
+                        unreachable!()
+                    };
+                    TokenStream::concat(vec![
+                        args.into(),
+                        TokenTree::Token(lo.to(self.prev_span), token::FatArrow).into(),
+                        body.into(),
+                    ])
+                } else {
+                    self.unexpected()?;
+                    unreachable!()
+                };
+
+                (ident, ast::MacroDef { tokens: tokens.into(), legacy: false })
+            }
+            token::Ident(ident) if ident.name == "macro_rules" &&
+                                   self.look_ahead(1, |t| *t == token::Not) => {
+                let prev_span = self.prev_span;
+                self.complain_if_pub_macro(vis, prev_span);
+                self.bump();
+                self.bump();
+
+                let ident = self.parse_ident()?;
+                let (delim, tokens) = self.expect_delimited_token_tree()?;
+                if delim != token::Brace {
+                    if !self.eat(&token::Semi) {
+                        let msg = "macros that expand to items must either \
+                                   be surrounded with braces or followed by a semicolon";
+                        self.span_err(self.prev_span, msg);
+                    }
                 }
+
+                (ident, ast::MacroDef { tokens: tokens, legacy: true })
             }
             _ => return Ok(None),
         };
 
-        let id = self.parse_ident()?;
-        let (delim, tts) = self.expect_delimited_token_tree()?;
-        if delim != token::Brace {
-            if !self.eat(&token::Semi) {
-                let msg = "macros that expand to items must either be surrounded with braces \
-                           or followed by a semicolon";
-                self.span_err(self.prev_span, msg);
-            }
-        }
-
         let span = lo.to(self.prev_span);
-        let kind = ItemKind::MacroDef(ast::MacroDef {
-            tokens: tts,
-        });
-        Ok(Some(self.mk_item(span, id, kind, Visibility::Inherited, attrs.to_owned())))
+        Ok(Some(self.mk_item(span, ident, ItemKind::MacroDef(def), vis.clone(), attrs.to_vec())))
     }
 
     fn parse_stmt_without_recovery(&mut self,
-- 
cgit 1.4.1-3-g733a5


From 7fdc1fb2e40bc8fc5f1f59eb3b9d180619bcb210 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Sat, 25 Mar 2017 21:14:18 +0000
Subject: Hygienize lifetimes.

---
 src/librustc/hir/lowering.rs             |  2 +-
 src/librustc/hir/map/def_collector.rs    |  2 +-
 src/librustc/hir/mod.rs                  |  2 +-
 src/librustc/middle/resolve_lifetime.rs  |  3 +--
 src/librustc_passes/ast_validation.rs    |  4 ++--
 src/librustc_save_analysis/lib.rs        |  2 +-
 src/libsyntax/ast.rs                     |  2 +-
 src/libsyntax/diagnostics/plugin.rs      |  2 +-
 src/libsyntax/ext/build.rs               | 12 ++++++------
 src/libsyntax/fold.rs                    |  2 +-
 src/libsyntax/parse/parser.rs            |  2 +-
 src/libsyntax/print/pprust.rs            |  2 +-
 src/libsyntax/test.rs                    |  2 +-
 src/libsyntax/visit.rs                   |  2 +-
 src/libsyntax_ext/deriving/generic/ty.rs | 12 ++++++------
 src/libsyntax_ext/env.rs                 |  7 +++----
 src/libsyntax_ext/format.rs              |  4 ++--
 17 files changed, 31 insertions(+), 33 deletions(-)

(limited to 'src/libsyntax/parse')

diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index f5c8d11caaa..5ef278207ed 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -985,7 +985,7 @@ impl<'a> LoweringContext<'a> {
     fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
         hir::Lifetime {
             id: self.lower_node_id(l.id),
-            name: l.name,
+            name: self.lower_ident(l.ident),
             span: l.span,
         }
     }
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 88750ce3acd..f834c744f95 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -283,7 +283,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
 
     fn visit_lifetime_def(&mut self, def: &'a LifetimeDef) {
         self.create_def(def.lifetime.id,
-                        DefPathData::LifetimeDef(def.lifetime.name.as_str()),
+                        DefPathData::LifetimeDef(def.lifetime.ident.name.as_str()),
                         REGULAR_SPACE);
     }
 
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 74a47b4e5b9..500e95a8a77 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -162,7 +162,7 @@ impl Lifetime {
     }
 
     pub fn is_static(&self) -> bool {
-        self.name == keywords::StaticLifetime.name()
+        self.name == "'static"
     }
 }
 
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 7d7308d73bb..1a07423bcbc 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -26,7 +26,6 @@ use std::mem::replace;
 use syntax::ast;
 use syntax::attr;
 use syntax::ptr::P;
-use syntax::symbol::keywords;
 use syntax_pos::Span;
 use errors::DiagnosticBuilder;
 use util::nodemap::{NodeMap, NodeSet, FxHashSet, FxHashMap, DefIdMap};
@@ -746,7 +745,7 @@ fn object_lifetime_defaults_for_item(hir_map: &Map, generics: &hir::Generics)
         match set {
             Set1::Empty => Set1::Empty,
             Set1::One(name) => {
-                if name == keywords::StaticLifetime.name() {
+                if name == "'static" {
                     Set1::One(Region::Static)
                 } else {
                     generics.lifetimes.iter().enumerate().find(|&(_, def)| {
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index d7fee7f3110..79d90210d47 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -103,11 +103,11 @@ impl<'a> AstValidator<'a> {
 
 impl<'a> Visitor<'a> for AstValidator<'a> {
     fn visit_lifetime(&mut self, lt: &'a Lifetime) {
-        if lt.name == "'_" {
+        if lt.ident.name == "'_" {
             self.session.add_lint(lint::builtin::LIFETIME_UNDERSCORE,
                                   lt.id,
                                   lt.span,
-                                  format!("invalid lifetime name `{}`", lt.name));
+                                  format!("invalid lifetime name `{}`", lt.ident));
         }
 
         visit::walk_lifetime(self, lt)
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 5a8acf9abe1..d83740936d5 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -828,7 +828,7 @@ fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String {
     if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() {
         sig.push('<');
         sig.push_str(&generics.lifetimes.iter()
-                              .map(|l| l.lifetime.name.to_string())
+                              .map(|l| l.lifetime.ident.name.to_string())
                               .collect::>()
                               .join(", "));
         if !generics.lifetimes.is_empty() {
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 3dcb77a0497..2eb39bc26b5 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -37,7 +37,7 @@ use std::u32;
 pub struct Lifetime {
     pub id: NodeId,
     pub span: Span,
-    pub name: Name
+    pub ident: Ident,
 }
 
 impl fmt::Debug for Lifetime {
diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs
index 73aeb40df84..2a5de3c7382 100644
--- a/src/libsyntax/diagnostics/plugin.rs
+++ b/src/libsyntax/diagnostics/plugin.rs
@@ -206,7 +206,7 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt,
             (descriptions.len(), ecx.expr_vec(span, descriptions))
         });
 
-    let static_ = ecx.lifetime(span, ecx.name_of("'static"));
+    let static_ = ecx.lifetime(span, Ident::from_str("'static"));
     let ty_str = ecx.ty_rptr(
         span,
         ecx.ty_ident(span, ecx.ident_of("str")),
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 09f22e8691e..a4580ea3939 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -76,10 +76,10 @@ pub trait AstBuilder {
     fn trait_ref(&self, path: ast::Path) -> ast::TraitRef;
     fn poly_trait_ref(&self, span: Span, path: ast::Path) -> ast::PolyTraitRef;
     fn typarambound(&self, path: ast::Path) -> ast::TyParamBound;
-    fn lifetime(&self, span: Span, ident: ast::Name) -> ast::Lifetime;
+    fn lifetime(&self, span: Span, ident: ast::Ident) -> ast::Lifetime;
     fn lifetime_def(&self,
                     span: Span,
-                    name: ast::Name,
+                    ident: ast::Ident,
                     attrs: Vec,
                     bounds: Vec)
                     -> ast::LifetimeDef;
@@ -478,19 +478,19 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         ast::TraitTyParamBound(self.poly_trait_ref(path.span, path), ast::TraitBoundModifier::None)
     }
 
-    fn lifetime(&self, span: Span, name: ast::Name) -> ast::Lifetime {
-        ast::Lifetime { id: ast::DUMMY_NODE_ID, span: span, name: name }
+    fn lifetime(&self, span: Span, ident: ast::Ident) -> ast::Lifetime {
+        ast::Lifetime { id: ast::DUMMY_NODE_ID, span: span, ident: ident }
     }
 
     fn lifetime_def(&self,
                     span: Span,
-                    name: ast::Name,
+                    ident: ast::Ident,
                     attrs: Vec,
                     bounds: Vec)
                     -> ast::LifetimeDef {
         ast::LifetimeDef {
             attrs: attrs.into(),
-            lifetime: self.lifetime(span, name),
+            lifetime: self.lifetime(span, ident),
             bounds: bounds
         }
     }
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 5bbda5f2689..4c6cf49a8db 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -694,7 +694,7 @@ pub fn noop_fold_ty_params(tps: Vec, fld: &mut T) -> Vec(l: Lifetime, fld: &mut T) -> Lifetime {
     Lifetime {
         id: fld.new_id(l.id),
-        name: l.name,
+        ident: fld.fold_ident(l.ident),
         span: fld.new_span(l.span)
     }
 }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index bc9be809ca4..8d7c8c5248b 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1958,7 +1958,7 @@ impl<'a> Parser<'a> {
             token::Lifetime(ident) => {
                 let ident_span = self.span;
                 self.bump();
-                Lifetime { name: ident.name, span: ident_span, id: ast::DUMMY_NODE_ID }
+                Lifetime { ident: ident, span: ident_span, id: ast::DUMMY_NODE_ID }
             }
             _ => self.span_bug(self.span, "not a lifetime")
         }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 6c5bf56070e..073ededcb0c 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -2764,7 +2764,7 @@ impl<'a> State<'a> {
                           lifetime: &ast::Lifetime)
                           -> io::Result<()>
     {
-        self.print_name(lifetime.name)
+        self.print_name(lifetime.ident.name)
     }
 
     pub fn print_lifetime_bounds(&mut self,
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 3df61fadc35..837c3eb0100 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -591,7 +591,7 @@ fn mk_tests(cx: &TestCtxt) -> P {
     let struct_type = ecx.ty_path(ecx.path(sp, vec![ecx.ident_of("self"),
                                                     ecx.ident_of("test"),
                                                     ecx.ident_of("TestDescAndFn")]));
-    let static_lt = ecx.lifetime(sp, keywords::StaticLifetime.name());
+    let static_lt = ecx.lifetime(sp, keywords::StaticLifetime.ident());
     // &'static [self::test::TestDescAndFn]
     let static_type = ecx.ty_rptr(sp,
                                   ecx.ty(sp, ast::TyKind::Slice(struct_type)),
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index d29d2497afe..18a0949af0e 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -195,7 +195,7 @@ pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) {
 }
 
 pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime) {
-    visitor.visit_name(lifetime.span, lifetime.name);
+    visitor.visit_ident(lifetime.span, lifetime.ident);
 }
 
 pub fn walk_lifetime_def<'a, V: Visitor<'a>>(visitor: &mut V, lifetime_def: &'a LifetimeDef) {
diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs
index cfd52381538..9c89f99cbb5 100644
--- a/src/libsyntax_ext/deriving/generic/ty.rs
+++ b/src/libsyntax_ext/deriving/generic/ty.rs
@@ -118,14 +118,14 @@ pub fn nil_ty<'r>() -> Ty<'r> {
 
 fn mk_lifetime(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Option {
     match *lt {
-        Some(ref s) => Some(cx.lifetime(span, cx.ident_of(*s).name)),
+        Some(s) => Some(cx.lifetime(span, Ident::from_str(s))),
         None => None,
     }
 }
 
 fn mk_lifetimes(cx: &ExtCtxt, span: Span, lt: &Option<&str>) -> Vec {
     match *lt {
-        Some(ref s) => vec![cx.lifetime(span, cx.ident_of(*s).name)],
+        Some(s) => vec![cx.lifetime(span, Ident::from_str(s))],
         None => vec![],
     }
 }
@@ -243,11 +243,11 @@ impl<'a> LifetimeBounds<'a> {
                        -> Generics {
         let lifetimes = self.lifetimes
             .iter()
-            .map(|&(ref lt, ref bounds)| {
+            .map(|&(lt, ref bounds)| {
                 let bounds = bounds.iter()
-                    .map(|b| cx.lifetime(span, cx.ident_of(*b).name))
+                    .map(|b| cx.lifetime(span, Ident::from_str(b)))
                     .collect();
-                cx.lifetime_def(span, cx.ident_of(*lt).name, vec![], bounds)
+                cx.lifetime_def(span, Ident::from_str(lt), vec![], bounds)
             })
             .collect();
         let ty_params = self.bounds
@@ -277,7 +277,7 @@ pub fn get_explicit_self(cx: &ExtCtxt,
                 respan(span,
                        match *ptr {
                            Borrowed(ref lt, mutbl) => {
-                               let lt = lt.map(|s| cx.lifetime(span, cx.ident_of(s).name));
+                               let lt = lt.map(|s| cx.lifetime(span, Ident::from_str(s)));
                                SelfKind::Region(lt, mutbl)
                            }
                            Raw(_) => {
diff --git a/src/libsyntax_ext/env.rs b/src/libsyntax_ext/env.rs
index ecf0a8f377e..affebbabbbd 100644
--- a/src/libsyntax_ext/env.rs
+++ b/src/libsyntax_ext/env.rs
@@ -13,7 +13,7 @@
 // interface.
 //
 
-use syntax::ast;
+use syntax::ast::{self, Ident};
 use syntax::ext::base::*;
 use syntax::ext::base;
 use syntax::ext::build::AstBuilder;
@@ -39,10 +39,9 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt,
                                      cx.std_path(&["option", "Option", "None"]),
                                      Vec::new(),
                                      vec![cx.ty_rptr(sp,
-                                                     cx.ty_ident(sp, cx.ident_of("str")),
+                                                     cx.ty_ident(sp, Ident::from_str("str")),
                                                      Some(cx.lifetime(sp,
-                                                                      cx.ident_of("'static")
-                                                                          .name)),
+                                                                      Ident::from_str("'static"))),
                                                      ast::Mutability::Immutable)],
                                      Vec::new()))
         }
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index 6f5ab50b2fe..24c1dfe289b 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -508,7 +508,7 @@ impl<'a, 'b> Context<'a, 'b> {
         let sp = piece_ty.span;
         let ty = ecx.ty_rptr(sp,
                              ecx.ty(sp, ast::TyKind::Slice(piece_ty)),
-                             Some(ecx.lifetime(sp, keywords::StaticLifetime.name())),
+                             Some(ecx.lifetime(sp, keywords::StaticLifetime.ident())),
                              ast::Mutability::Immutable);
         let slice = ecx.expr_vec_slice(sp, pieces);
         // static instead of const to speed up codegen by not requiring this to be inlined
@@ -536,7 +536,7 @@ impl<'a, 'b> Context<'a, 'b> {
 
         // First, build up the static array which will become our precompiled
         // format "string"
-        let static_lifetime = self.ecx.lifetime(self.fmtsp, keywords::StaticLifetime.name());
+        let static_lifetime = self.ecx.lifetime(self.fmtsp, keywords::StaticLifetime.ident());
         let piece_ty = self.ecx.ty_rptr(self.fmtsp,
                                         self.ecx.ty_ident(self.fmtsp, self.ecx.ident_of("str")),
                                         Some(static_lifetime),
-- 
cgit 1.4.1-3-g733a5