From 64314e3ae218cb004735735667581f12df8461ef Mon Sep 17 00:00:00 2001 From: Taylor Cramer Date: Mon, 18 Sep 2017 22:55:21 -0700 Subject: Implement underscore lifetimes --- src/libsyntax/feature_gate.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 6560943a932..1fef382c83a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -389,6 +389,9 @@ declare_features! ( // Copy/Clone closures (RFC 2132) (active, clone_closures, "1.22.0", Some(44490)), (active, copy_closures, "1.22.0", Some(44490)), + + // allow `'_` placeholder lifetimes + (active, underscore_lifetimes, "1.22.0", Some(44524)), ); declare_features! ( @@ -1572,6 +1575,14 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } visit::walk_lifetime_def(self, lifetime_def) } + + fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) { + if lt.ident.name == "'_" { + gate_feature_post!(&self, underscore_lifetimes, lt.span, + "underscore lifetimes are unstable"); + } + visit::walk_lifetime(self, lt) + } } pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute]) -> Features { -- cgit 1.4.1-3-g733a5 From ded73a85e2dd258e81db19d9320f87e5389ae87a Mon Sep 17 00:00:00 2001 From: Seiichi Uchida Date: Fri, 22 Sep 2017 01:19:34 +0900 Subject: Include unary operator to span for ExprKind::Unary --- src/libsyntax/parse/parser.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a2514a04254..3829be40a1e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2632,7 +2632,7 @@ impl<'a> Parser<'a> { self.bump(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - (span, self.mk_unary(UnOp::Not, e)) + (lo.to(span), self.mk_unary(UnOp::Not, e)) } // Suggest `!` for bitwise negation when encountering a `~` token::Tilde => { @@ -2645,26 +2645,26 @@ impl<'a> Parser<'a> { 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)) + (lo.to(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)?; - (span, self.mk_unary(UnOp::Neg, e)) + (lo.to(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)?; - (span, self.mk_unary(UnOp::Deref, e)) + (lo.to(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)?; - (span, ExprKind::AddrOf(m, e)) + (lo.to(span), ExprKind::AddrOf(m, e)) } token::Ident(..) if self.token.is_keyword(keywords::In) => { self.bump(); @@ -2675,13 +2675,13 @@ impl<'a> Parser<'a> { let blk = self.parse_block()?; let span = blk.span; let blk_expr = self.mk_expr(span, ExprKind::Block(blk), ThinVec::new()); - (span, ExprKind::InPlace(place, blk_expr)) + (lo.to(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)?; - (span, ExprKind::Box(e)) + (lo.to(span), ExprKind::Box(e)) } _ => return self.parse_dot_or_call_expr(Some(attrs)) }; -- cgit 1.4.1-3-g733a5 From 35176867f62f76b9bc27267878f2d74d9c776221 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Tue, 22 Aug 2017 19:22:52 -0700 Subject: only set non-ADT derive error once per attribute, not per trait A slight eccentricity of this change is that now non-ADT-derive errors prevent derive-macro-not-found errors from surfacing (see changes to the gating-of-derive compile-fail tests). Resolves #43927. --- src/libsyntax/ext/expand.rs | 18 ++++++++++++++++ src/libsyntax_ext/deriving/generic/mod.rs | 11 ++++++---- .../feature-gate/issue-43106-gating-of-derive-2.rs | 24 +--------------------- .../feature-gate/issue-43106-gating-of-derive.rs | 5 ++--- src/test/ui/span/issue-43927-non-ADT-derive.rs | 16 +++++++++++++++ src/test/ui/span/issue-43927-non-ADT-derive.stderr | 8 ++++++++ 6 files changed, 52 insertions(+), 30 deletions(-) create mode 100644 src/test/ui/span/issue-43927-non-ADT-derive.rs create mode 100644 src/test/ui/span/issue-43927-non-ADT-derive.stderr (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index de9c085cc78..3a1b9342530 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -282,6 +282,24 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let expansion = self.expand_invoc(invoc, ext); self.collect_invocations(expansion, &[]) } else if let InvocationKind::Attr { attr: None, traits, item } = invoc.kind { + let derive_allowed = match item { + Annotatable::Item(ref item) => match item.node { + ast::ItemKind::Struct(..) | + ast::ItemKind::Enum(..) | + ast::ItemKind::Union(..) => true, + _ => false, + }, + _ => false, + }; + if !derive_allowed { + let span = item.attrs().iter() + .find(|attr| attr.check_name("derive")) + .expect("`derive` attribute should exist").span; + self.cx.span_err(span, + "`derive` may only be applied to structs, enums \ + and unions"); + } + let item = item .map_attrs(|mut attrs| { attrs.retain(|a| a.path != "derive"); attrs }); let item_with_markers = diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index d701810e2e9..5c1ca19d635 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -428,8 +428,9 @@ impl<'a> TraitDef<'a> { } } _ => { - cx.span_err(mitem.span, - "`derive` may only be applied to structs, enums and unions"); + // Non-ADT derive is an error, but it should have been + // set earlier; see + // libsyntax/ext/expand.rs:MacroExpander::expand() return; } }; @@ -448,8 +449,10 @@ impl<'a> TraitDef<'a> { push(Annotatable::Item(P(ast::Item { attrs: attrs, ..(*newitem).clone() }))) } _ => { - cx.span_err(mitem.span, - "`derive` may only be applied to structs and enums"); + // Non-Item derive is an error, but it should have been + // set earlier; see + // libsyntax/ext/expand.rs:MacroExpander::expand() + return; } } } diff --git a/src/test/compile-fail/feature-gate/issue-43106-gating-of-derive-2.rs b/src/test/compile-fail/feature-gate/issue-43106-gating-of-derive-2.rs index be82d0a5f6d..2dbc6cb140d 100644 --- a/src/test/compile-fail/feature-gate/issue-43106-gating-of-derive-2.rs +++ b/src/test/compile-fail/feature-gate/issue-43106-gating-of-derive-2.rs @@ -8,23 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// `#![derive]` is interpreted (and raises errors) when it occurs at -// contexts other than ADT definitions. This test checks cases where -// the derive-macro does not exist. +// This test checks cases where the derive-macro does not exist. -#![derive(x3300)] -//~^ ERROR cannot find derive macro `x3300` in this scope - -#[derive(x3300)] -//~^ ERROR cannot find derive macro `x3300` in this scope mod derive { - mod inner { #![derive(x3300)] } - //~^ ERROR cannot find derive macro `x3300` in this scope - - #[derive(x3300)] - //~^ ERROR cannot find derive macro `x3300` in this scope - fn derive() { } - #[derive(x3300)] //~^ ERROR cannot find derive macro `x3300` in this scope union U { f: i32 } @@ -36,12 +22,4 @@ mod derive { #[derive(x3300)] //~^ ERROR cannot find derive macro `x3300` in this scope struct S; - - #[derive(x3300)] - //~^ ERROR cannot find derive macro `x3300` in this scope - type T = S; - - #[derive(x3300)] - //~^ ERROR cannot find derive macro `x3300` in this scope - impl S { } } diff --git a/src/test/compile-fail/feature-gate/issue-43106-gating-of-derive.rs b/src/test/compile-fail/feature-gate/issue-43106-gating-of-derive.rs index 41c3d0ef561..e5293ebb94d 100644 --- a/src/test/compile-fail/feature-gate/issue-43106-gating-of-derive.rs +++ b/src/test/compile-fail/feature-gate/issue-43106-gating-of-derive.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// `#![derive]` is interpreted (and raises errors) when it occurs at -// contexts other than ADT definitions. This test checks cases where -// the derive-macro exists. +// `#![derive]` raises errors when it occurs at contexts other than ADT +// definitions. #![derive(Debug)] //~^ ERROR `derive` may only be applied to structs, enums and unions diff --git a/src/test/ui/span/issue-43927-non-ADT-derive.rs b/src/test/ui/span/issue-43927-non-ADT-derive.rs new file mode 100644 index 00000000000..cf2a4b8d037 --- /dev/null +++ b/src/test/ui/span/issue-43927-non-ADT-derive.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. + +#![allow(dead_code)] + +#![derive(Debug, PartialEq, Eq)] // should be an outer attribute! +struct DerivedOn; + +fn main() {} diff --git a/src/test/ui/span/issue-43927-non-ADT-derive.stderr b/src/test/ui/span/issue-43927-non-ADT-derive.stderr new file mode 100644 index 00000000000..4cfbb6d6af0 --- /dev/null +++ b/src/test/ui/span/issue-43927-non-ADT-derive.stderr @@ -0,0 +1,8 @@ +error: `derive` may only be applied to structs, enums and unions + --> $DIR/issue-43927-non-ADT-derive.rs:13:1 + | +13 | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute! + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 083f053294b062e12bacfea17a07f83e1b4c3732 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Thu, 21 Sep 2017 20:29:29 -0700 Subject: suggest an outer attribute when `#![derive(...)]` (predictably) fails --- src/libsyntax/ext/base.rs | 4 ++++ src/libsyntax/ext/expand.rs | 18 +++++++++++++----- src/test/ui/span/issue-43927-non-ADT-derive.stderr | 2 +- 3 files changed, 18 insertions(+), 6 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index c139cfeaebf..0e05cce35e2 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -783,6 +783,10 @@ impl<'a> ExtCtxt<'a> { pub fn span_err(&self, sp: Span, msg: &str) { self.parse_sess.span_diagnostic.span_err(sp, msg); } + pub fn mut_span_err(&self, sp: Span, msg: &str) + -> DiagnosticBuilder<'a> { + self.parse_sess.span_diagnostic.mut_span_err(sp, msg) + } pub fn span_warn(&self, sp: Span, msg: &str) { self.parse_sess.span_diagnostic.span_warn(sp, msg); } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 3a1b9342530..5deb4c3cc00 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -292,12 +292,20 @@ impl<'a, 'b> MacroExpander<'a, 'b> { _ => false, }; if !derive_allowed { - let span = item.attrs().iter() + let attr = item.attrs().iter() .find(|attr| attr.check_name("derive")) - .expect("`derive` attribute should exist").span; - self.cx.span_err(span, - "`derive` may only be applied to structs, enums \ - and unions"); + .expect("`derive` attribute should exist"); + let span = attr.span; + let mut err = self.cx.mut_span_err(span, + "`derive` may only be applied to \ + structs, enums and unions"); + if let ast::AttrStyle::Inner = attr.style { + let trait_list = traits.iter() + .map(|t| format!("{}", t)).collect::>(); + let suggestion = format!("#[derive({})]", trait_list.join(", ")); + err.span_suggestion(span, "try an outer attribute", suggestion); + } + err.emit(); } let item = item diff --git a/src/test/ui/span/issue-43927-non-ADT-derive.stderr b/src/test/ui/span/issue-43927-non-ADT-derive.stderr index 4cfbb6d6af0..a0485bed2f4 100644 --- a/src/test/ui/span/issue-43927-non-ADT-derive.stderr +++ b/src/test/ui/span/issue-43927-non-ADT-derive.stderr @@ -2,7 +2,7 @@ error: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43927-non-ADT-derive.rs:13:1 | 13 | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute! - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Debug, PartialEq, Eq)]` error: aborting due to previous error -- cgit 1.4.1-3-g733a5 From e64efc91f49affb265328e354c8c8f0544daa462 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Tue, 19 Sep 2017 05:40:04 +0000 Subject: Add support for `..=` syntax Add ..= to the parser Add ..= to libproc_macro Add ..= to ICH Highlight ..= in rustdoc Update impl Debug for RangeInclusive to ..= Replace `...` to `..=` in range docs Make the dotdoteq warning point to the ... Add warning for ... in expressions Updated more tests to the ..= syntax Updated even more tests to the ..= syntax Updated the inclusive_range entry in unstable book --- .../language-features/inclusive-range-syntax.md | 4 +- src/liballoc/tests/btree/map.rs | 28 ++++----- src/liballoc/tests/str.rs | 16 ++--- src/liballoc/tests/string.rs | 6 +- src/liballoc/tests/vec.rs | 28 ++++----- src/libcore/ops/range.rs | 50 ++++++++-------- src/libcore/slice/mod.rs | 4 ++ src/libcore/tests/iter.rs | 32 +++++----- src/libproc_macro/lib.rs | 2 + src/libproc_macro/quote.rs | 4 +- src/librustc/ich/impls_syntax.rs | 2 + src/librustdoc/html/highlight.rs | 6 +- src/libsyntax/diagnostic_list.rs | 4 +- src/libsyntax/ext/quote.rs | 2 + src/libsyntax/feature_gate.rs | 2 +- src/libsyntax/parse/lexer/mod.rs | 3 + src/libsyntax/parse/parser.rs | 50 +++++++++++----- src/libsyntax/parse/token.rs | 35 ++++++----- src/libsyntax/print/pprust.rs | 2 + src/libsyntax/util/parser.rs | 17 +++--- src/test/compile-fail/E0586.rs | 2 +- src/test/compile-fail/impossible_range.rs | 8 +-- src/test/compile-fail/range_inclusive_gate.rs | 2 +- .../incremental/hashes/indexing_expressions.rs | 2 +- src/test/parse-fail/pat-ranges-1.rs | 2 +- src/test/parse-fail/pat-ranges-2.rs | 2 +- src/test/parse-fail/pat-ranges-3.rs | 2 +- src/test/parse-fail/pat-ranges-4.rs | 3 +- src/test/parse-fail/range_inclusive.rs | 2 +- src/test/parse-fail/range_inclusive_gate.rs | 14 ++--- src/test/run-pass/inc-range-pat.rs | 20 +++++++ src/test/run-pass/range_inclusive.rs | 68 +++++++++++----------- src/test/run-pass/range_inclusive_gate.rs | 2 +- 33 files changed, 244 insertions(+), 182 deletions(-) create mode 100644 src/test/run-pass/inc-range-pat.rs (limited to 'src/libsyntax') diff --git a/src/doc/unstable-book/src/language-features/inclusive-range-syntax.md b/src/doc/unstable-book/src/language-features/inclusive-range-syntax.md index 255445c318d..56f58803150 100644 --- a/src/doc/unstable-book/src/language-features/inclusive-range-syntax.md +++ b/src/doc/unstable-book/src/language-features/inclusive-range-syntax.md @@ -7,13 +7,13 @@ The tracking issue for this feature is: [#28237] ------------------------ To get a range that goes from 0 to 10 and includes the value 10, you -can write `0...10`: +can write `0..=10`: ```rust #![feature(inclusive_range_syntax)] fn main() { - for i in 0...10 { + for i in 0..=10 { println!("{}", i); } } diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index 2c899d96940..2393101040d 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -182,7 +182,7 @@ fn test_range_small() { fn test_range_inclusive() { let size = 500; - let map: BTreeMap<_, _> = (0...size).map(|i| (i, i)).collect(); + let map: BTreeMap<_, _> = (0..=size).map(|i| (i, i)).collect(); fn check<'a, L, R>(lhs: L, rhs: R) where L: IntoIterator, @@ -193,18 +193,18 @@ fn test_range_inclusive() { assert_eq!(lhs, rhs); } - check(map.range(size + 1...size + 1), vec![]); - check(map.range(size...size), vec![(&size, &size)]); - check(map.range(size...size + 1), vec![(&size, &size)]); - check(map.range(0...0), vec![(&0, &0)]); - check(map.range(0...size - 1), map.range(..size)); - check(map.range(-1...-1), vec![]); - check(map.range(-1...size), map.range(..)); - check(map.range(...size), map.range(..)); - check(map.range(...200), map.range(..201)); - check(map.range(5...8), vec![(&5, &5), (&6, &6), (&7, &7), (&8, &8)]); - check(map.range(-1...0), vec![(&0, &0)]); - check(map.range(-1...2), vec![(&0, &0), (&1, &1), (&2, &2)]); + check(map.range(size + 1..=size + 1), vec![]); + check(map.range(size..=size), vec![(&size, &size)]); + check(map.range(size..=size + 1), vec![(&size, &size)]); + check(map.range(0..=0), vec![(&0, &0)]); + check(map.range(0..=size - 1), map.range(..size)); + check(map.range(-1..=-1), vec![]); + check(map.range(-1..=size), map.range(..)); + check(map.range(..=size), map.range(..)); + check(map.range(..=200), map.range(..201)); + check(map.range(5..=8), vec![(&5, &5), (&6, &6), (&7, &7), (&8, &8)]); + check(map.range(-1..=0), vec![(&0, &0)]); + check(map.range(-1..=2), vec![(&0, &0), (&1, &1), (&2, &2)]); } #[test] @@ -212,7 +212,7 @@ fn test_range_inclusive_max_value() { let max = ::std::usize::MAX; let map: BTreeMap<_, _> = vec![(max, 0)].into_iter().collect(); - assert_eq!(map.range(max...max).collect::>(), &[(&max, &0)]); + assert_eq!(map.range(max..=max).collect::>(), &[(&max, &0)]); } #[test] diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index 9d8ca38b20e..b3178064505 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -361,13 +361,13 @@ fn test_slice_fail() { #[test] #[should_panic] fn test_str_slice_rangetoinclusive_max_panics() { - &"hello"[...usize::max_value()]; + &"hello"[..=usize::max_value()]; } #[test] #[should_panic] fn test_str_slice_rangeinclusive_max_panics() { - &"hello"[1...usize::max_value()]; + &"hello"[1..=usize::max_value()]; } #[test] @@ -375,7 +375,7 @@ fn test_str_slice_rangeinclusive_max_panics() { fn test_str_slicemut_rangetoinclusive_max_panics() { let mut s = "hello".to_owned(); let s: &mut str = &mut s; - &mut s[...usize::max_value()]; + &mut s[..=usize::max_value()]; } #[test] @@ -383,7 +383,7 @@ fn test_str_slicemut_rangetoinclusive_max_panics() { fn test_str_slicemut_rangeinclusive_max_panics() { let mut s = "hello".to_owned(); let s: &mut str = &mut s; - &mut s[1...usize::max_value()]; + &mut s[1..=usize::max_value()]; } #[test] @@ -391,13 +391,13 @@ fn test_str_get_maxinclusive() { let mut s = "hello".to_owned(); { let s: &str = &s; - assert_eq!(s.get(...usize::max_value()), None); - assert_eq!(s.get(1...usize::max_value()), None); + assert_eq!(s.get(..=usize::max_value()), None); + assert_eq!(s.get(1..=usize::max_value()), None); } { let s: &mut str = &mut s; - assert_eq!(s.get(...usize::max_value()), None); - assert_eq!(s.get(1...usize::max_value()), None); + assert_eq!(s.get(..=usize::max_value()), None); + assert_eq!(s.get(1..=usize::max_value()), None); } } diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index 6aba18ddf49..ef6f5e10a72 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -456,9 +456,9 @@ fn test_splice_char_boundary() { #[test] fn test_splice_inclusive_range() { let mut v = String::from("12345"); - v.splice(2...3, "789"); + v.splice(2..=3, "789"); assert_eq!(v, "127895"); - v.splice(1...2, "A"); + v.splice(1..=2, "A"); assert_eq!(v, "1A895"); } @@ -473,7 +473,7 @@ fn test_splice_out_of_bounds() { #[should_panic] fn test_splice_inclusive_out_of_bounds() { let mut s = String::from("12345"); - s.splice(5...5, "789"); + s.splice(5..=5, "789"); } #[test] diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 670ea8089fc..0e25da5bd30 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -537,27 +537,27 @@ fn test_drain_range() { #[test] fn test_drain_inclusive_range() { let mut v = vec!['a', 'b', 'c', 'd', 'e']; - for _ in v.drain(1...3) { + for _ in v.drain(1..=3) { } assert_eq!(v, &['a', 'e']); - let mut v: Vec<_> = (0...5).map(|x| x.to_string()).collect(); - for _ in v.drain(1...5) { + let mut v: Vec<_> = (0..=5).map(|x| x.to_string()).collect(); + for _ in v.drain(1..=5) { } assert_eq!(v, &["0".to_string()]); - let mut v: Vec = (0...5).map(|x| x.to_string()).collect(); - for _ in v.drain(0...5) { + let mut v: Vec = (0..=5).map(|x| x.to_string()).collect(); + for _ in v.drain(0..=5) { } assert_eq!(v, Vec::::new()); - let mut v: Vec<_> = (0...5).map(|x| x.to_string()).collect(); - for _ in v.drain(0...3) { + let mut v: Vec<_> = (0..=5).map(|x| x.to_string()).collect(); + for _ in v.drain(0..=3) { } assert_eq!(v, &["4".to_string(), "5".to_string()]); - let mut v: Vec<_> = (0...1).map(|x| x.to_string()).collect(); - for _ in v.drain(...0) { + let mut v: Vec<_> = (0..=1).map(|x| x.to_string()).collect(); + for _ in v.drain(..=0) { } assert_eq!(v, &["1".to_string()]); } @@ -572,7 +572,7 @@ fn test_drain_max_vec_size() { let mut v = Vec::<()>::with_capacity(usize::max_value()); unsafe { v.set_len(usize::max_value()); } - for _ in v.drain(usize::max_value() - 1...usize::max_value() - 1) { + for _ in v.drain(usize::max_value() - 1..=usize::max_value() - 1) { } assert_eq!(v.len(), usize::max_value() - 1); } @@ -581,7 +581,7 @@ fn test_drain_max_vec_size() { #[should_panic] fn test_drain_inclusive_out_of_bounds() { let mut v = vec![1, 2, 3, 4, 5]; - v.drain(5...5); + v.drain(5..=5); } #[test] @@ -598,10 +598,10 @@ fn test_splice() { fn test_splice_inclusive_range() { let mut v = vec![1, 2, 3, 4, 5]; let a = [10, 11, 12]; - let t1: Vec<_> = v.splice(2...3, a.iter().cloned()).collect(); + let t1: Vec<_> = v.splice(2..=3, a.iter().cloned()).collect(); assert_eq!(v, &[1, 2, 10, 11, 12, 5]); assert_eq!(t1, &[3, 4]); - let t2: Vec<_> = v.splice(1...2, Some(20)).collect(); + let t2: Vec<_> = v.splice(1..=2, Some(20)).collect(); assert_eq!(v, &[1, 20, 11, 12, 5]); assert_eq!(t2, &[2, 10]); } @@ -619,7 +619,7 @@ fn test_splice_out_of_bounds() { fn test_splice_inclusive_out_of_bounds() { let mut v = vec![1, 2, 3, 4, 5]; let a = [10, 11, 12]; - v.splice(5...5, a.iter().cloned()); + v.splice(5..=5, a.iter().cloned()); } #[test] diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 463a50491a8..3f573f7c7eb 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -241,9 +241,9 @@ impl> RangeTo { } } -/// An range bounded inclusively below and above (`start...end`). +/// An range bounded inclusively below and above (`start..=end`). /// -/// The `RangeInclusive` `start...end` contains all values with `x >= start` +/// The `RangeInclusive` `start..=end` contains all values with `x >= start` /// and `x <= end`. /// /// # Examples @@ -251,12 +251,12 @@ impl> RangeTo { /// ``` /// #![feature(inclusive_range,inclusive_range_syntax)] /// -/// assert_eq!((3...5), std::ops::RangeInclusive { start: 3, end: 5 }); -/// assert_eq!(3 + 4 + 5, (3...5).sum()); +/// assert_eq!((3..=5), std::ops::RangeInclusive { start: 3, end: 5 }); +/// assert_eq!(3 + 4 + 5, (3..=5).sum()); /// /// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ ...2], [0,1,2 ]); -/// assert_eq!(arr[1...2], [ 1,2 ]); // RangeInclusive +/// assert_eq!(arr[ ..=2], [0,1,2 ]); +/// assert_eq!(arr[1..=2], [ 1,2 ]); // RangeInclusive /// ``` #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] @@ -276,7 +276,7 @@ pub struct RangeInclusive { #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] impl fmt::Debug for RangeInclusive { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{:?}...{:?}", self.start, self.end) + write!(fmt, "{:?}..={:?}", self.start, self.end) } } @@ -289,32 +289,32 @@ impl> RangeInclusive { /// ``` /// #![feature(range_contains,inclusive_range_syntax)] /// - /// assert!(!(3...5).contains(2)); - /// assert!( (3...5).contains(3)); - /// assert!( (3...5).contains(4)); - /// assert!( (3...5).contains(5)); - /// assert!(!(3...5).contains(6)); + /// assert!(!(3..=5).contains(2)); + /// assert!( (3..=5).contains(3)); + /// assert!( (3..=5).contains(4)); + /// assert!( (3..=5).contains(5)); + /// assert!(!(3..=5).contains(6)); /// - /// assert!( (3...3).contains(3)); - /// assert!(!(3...2).contains(3)); + /// assert!( (3..=3).contains(3)); + /// assert!(!(3..=2).contains(3)); /// ``` pub fn contains(&self, item: Idx) -> bool { self.start <= item && item <= self.end } } -/// A range only bounded inclusively above (`...end`). +/// A range only bounded inclusively above (`..=end`). /// -/// The `RangeToInclusive` `...end` contains all values with `x <= end`. +/// The `RangeToInclusive` `..=end` contains all values with `x <= end`. /// It cannot serve as an [`Iterator`] because it doesn't have a starting point. /// /// # Examples /// -/// The `...end` syntax is a `RangeToInclusive`: +/// The `..=end` syntax is a `RangeToInclusive`: /// /// ``` /// #![feature(inclusive_range,inclusive_range_syntax)] -/// assert_eq!((...5), std::ops::RangeToInclusive{ end: 5 }); +/// assert_eq!((..=5), std::ops::RangeToInclusive{ end: 5 }); /// ``` /// /// It does not have an [`IntoIterator`] implementation, so you can't use it in a @@ -325,7 +325,7 @@ impl> RangeInclusive { /// /// // error[E0277]: the trait bound `std::ops::RangeToInclusive<{integer}>: /// // std::iter::Iterator` is not satisfied -/// for i in ...5 { +/// for i in ..=5 { /// // ... /// } /// ``` @@ -337,8 +337,8 @@ impl> RangeInclusive { /// #![feature(inclusive_range_syntax)] /// /// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ ...2], [0,1,2 ]); // RangeToInclusive -/// assert_eq!(arr[1...2], [ 1,2 ]); +/// assert_eq!(arr[ ..=2], [0,1,2 ]); // RangeToInclusive +/// assert_eq!(arr[1..=2], [ 1,2 ]); /// ``` /// /// [`IntoIterator`]: ../iter/trait.Iterator.html @@ -357,7 +357,7 @@ pub struct RangeToInclusive { #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] impl fmt::Debug for RangeToInclusive { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "...{:?}", self.end) + write!(fmt, "..={:?}", self.end) } } @@ -370,9 +370,9 @@ impl> RangeToInclusive { /// ``` /// #![feature(range_contains,inclusive_range_syntax)] /// - /// assert!( (...5).contains(-1_000_000_000)); - /// assert!( (...5).contains(5)); - /// assert!(!(...5).contains(6)); + /// assert!( (..=5).contains(-1_000_000_000)); + /// assert!( (..=5).contains(5)); + /// assert!(!(..=5).contains(6)); /// ``` pub fn contains(&self, item: Idx) -> bool { (item <= self.end) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index dacc014955a..c52e88170ae 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -16,6 +16,10 @@ #![stable(feature = "rust1", since = "1.0.0")] +// FIXME: replace remaining ... by ..= after next stage0 +// Silence warning: "... is being replaced by ..=" +#![cfg_attr(not(stage0), allow(warnings))] + // How this module is organized. // // The library infrastructure for slices is fairly messy. There's diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 59ae30de452..3c4ea974fc9 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1094,21 +1094,21 @@ fn test_range() { #[test] fn test_range_inclusive_exhaustion() { - let mut r = 10...10; + let mut r = 10..=10; assert_eq!(r.next(), Some(10)); - assert_eq!(r, 1...0); + assert_eq!(r, 1..=0); - let mut r = 10...10; + let mut r = 10..=10; assert_eq!(r.next_back(), Some(10)); - assert_eq!(r, 1...0); + assert_eq!(r, 1..=0); - let mut r = 10...12; + let mut r = 10..=12; assert_eq!(r.nth(2), Some(12)); - assert_eq!(r, 1...0); + assert_eq!(r, 1..=0); - let mut r = 10...12; + let mut r = 10..=12; assert_eq!(r.nth(5), None); - assert_eq!(r, 1...0); + assert_eq!(r, 1..=0); } @@ -1145,20 +1145,20 @@ fn test_range_from_nth() { #[test] fn test_range_inclusive_nth() { - assert_eq!((10...15).nth(0), Some(10)); - assert_eq!((10...15).nth(1), Some(11)); - assert_eq!((10...15).nth(5), Some(15)); - assert_eq!((10...15).nth(6), None); + assert_eq!((10..=15).nth(0), Some(10)); + assert_eq!((10..=15).nth(1), Some(11)); + assert_eq!((10..=15).nth(5), Some(15)); + assert_eq!((10..=15).nth(6), None); - let mut r = 10_u8...20; + let mut r = 10_u8..=20; assert_eq!(r.nth(2), Some(12)); - assert_eq!(r, 13...20); + assert_eq!(r, 13..=20); assert_eq!(r.nth(2), Some(15)); - assert_eq!(r, 16...20); + assert_eq!(r, 16..=20); assert_eq!(r.is_empty(), false); assert_eq!(r.nth(10), None); assert_eq!(r.is_empty(), true); - assert_eq!(r, 1...0); // We may not want to document/promise this detail + assert_eq!(r, 1..=0); // We may not want to document/promise this detail } #[test] diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 07e933985a0..2c540c8de8f 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -509,6 +509,7 @@ impl TokenTree { Dot => op!('.'), DotDot => joint!('.', Dot), DotDotDot => joint!('.', DotDot), + DotDotEq => joint!('.', DotEq), Comma => op!(','), Semi => op!(';'), Colon => op!(':'), @@ -531,6 +532,7 @@ impl TokenTree { }) } + DotEq => unreachable!(), OpenDelim(..) | CloseDelim(..) => unreachable!(), Whitespace | Comment | Shebang(..) | Eof => unreachable!(), }; diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs index 0db2b86b15f..8c1f6bfc11a 100644 --- a/src/libproc_macro/quote.rs +++ b/src/libproc_macro/quote.rs @@ -202,8 +202,8 @@ impl Quote for Token { gen_match! { Eq, Lt, Le, EqEq, Ne, Ge, Gt, AndAnd, OrOr, Not, Tilde, At, Dot, DotDot, DotDotDot, - Comma, Semi, Colon, ModSep, RArrow, LArrow, FatArrow, Pound, Dollar, Question, - Underscore; + DotDotEq, Comma, Semi, Colon, ModSep, RArrow, LArrow, FatArrow, Pound, Dollar, + Question, Underscore; Token::OpenDelim(delim) => quote!(rt::token::OpenDelim((quote delim))), Token::CloseDelim(delim) => quote!(rt::token::CloseDelim((quote delim))), diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 56ec6a65eb6..669e1ba773e 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -272,6 +272,8 @@ fn hash_token<'gcx, W: StableHasherResult>(token: &token::Token, token::Token::Dot | token::Token::DotDot | token::Token::DotDotDot | + token::Token::DotDotEq | + token::Token::DotEq | token::Token::Comma | token::Token::Semi | token::Token::Colon | diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 081f950e40d..98863b229b5 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -249,8 +249,8 @@ impl<'a> Classifier<'a> { token::BinOpEq(..) | token::FatArrow => Class::Op, // Miscellaneous, no highlighting. - token::Dot | token::DotDot | token::DotDotDot | token::Comma | token::Semi | - token::Colon | token::ModSep | token::LArrow | token::OpenDelim(_) | + token::Dot | token::DotDot | token::DotDotDot | token::DotDotEq | token::Comma | + token::Semi | token::Colon | token::ModSep | token::LArrow | token::OpenDelim(_) | token::CloseDelim(token::Brace) | token::CloseDelim(token::Paren) | token::CloseDelim(token::NoDelim) => Class::None, @@ -353,7 +353,7 @@ impl<'a> Classifier<'a> { token::Lifetime(..) => Class::Lifetime, token::Underscore | token::Eof | token::Interpolated(..) | - token::Tilde | token::At => Class::None, + token::Tilde | token::At | token::DotEq => Class::None, }; // Anything that didn't return above is the simple case where we the diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index b29883670bd..c3cf4747835 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -291,7 +291,7 @@ Erroneous code example: fn main() { let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1]; - let x = &tmp[1...]; // error: inclusive range was used with no end + let x = &tmp[1..=]; // error: inclusive range was used with no end } ``` @@ -312,7 +312,7 @@ Or put an end to your inclusive range: fn main() { let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1]; - let x = &tmp[1...3]; // ok! + let x = &tmp[1..=3]; // ok! } ``` "##, diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index c3f3a59c302..bd8c9a0ed40 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -686,7 +686,9 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P { token::At => "At", token::Dot => "Dot", token::DotDot => "DotDot", + token::DotEq => "DotEq", token::DotDotDot => "DotDotDot", + token::DotDotEq => "DotDotEq", token::Comma => "Comma", token::Semi => "Semi", token::Colon => "Colon", diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1fef382c83a..2fc451d5d00 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -261,7 +261,7 @@ declare_features! ( // rustc internal (active, abi_vectorcall, "1.7.0", None), - // a...b and ...b + // a..=b and ..=b (active, inclusive_range_syntax, "1.7.0", Some(28237)), // X..Y patterns diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index ce3f16d2ba1..1cb7b0eca58 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1131,6 +1131,9 @@ impl<'a> StringReader<'a> { if self.ch_is('.') { self.bump(); Ok(token::DotDotDot) + } else if self.ch_is('=') { + self.bump(); + Ok(token::DotDotEq) } else { Ok(token::DotDot) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a2514a04254..80c976abd19 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -432,7 +432,7 @@ impl Error { Error::InclusiveRangeWithNoEnd => { let mut err = struct_span_err!(handler, sp, E0586, "inclusive range with no end"); - err.help("inclusive ranges must be bounded at the end (`...b` or `a...b`)"); + err.help("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)"); err } } @@ -2710,7 +2710,7 @@ impl<'a> Parser<'a> { LhsExpr::AttributesParsed(attrs) => Some(attrs), _ => None, }; - if self.token == token::DotDot || self.token == token::DotDotDot { + if [token::DotDot, token::DotDotDot, token::DotDotEq].contains(&self.token) { return self.parse_prefix_range_expr(attrs); } else { self.parse_prefix_expr(attrs)? @@ -2744,6 +2744,10 @@ impl<'a> Parser<'a> { if op.precedence() < min_prec { break; } + // Warn about deprecated ... syntax (until SNAP) + if self.token == token::DotDotDot { + self.warn_dotdoteq(self.span); + } self.bump(); if op.is_comparison() { self.check_no_chained_comparison(&lhs, &op); @@ -2770,12 +2774,13 @@ impl<'a> Parser<'a> { } }; continue - } else if op == AssocOp::DotDot || op == AssocOp::DotDotDot { - // If we didn’t have to handle `x..`/`x...`, it would be pretty easy to + } else if op == AssocOp::DotDot || op == AssocOp::DotDotEq { + // If we didn’t have to handle `x..`/`x..=`, it would be pretty easy to // generalise it to the Fixity::None code. // - // We have 2 alternatives here: `x..y`/`x...y` and `x..`/`x...` The other + // We have 2 alternatives here: `x..y`/`x..=y` and `x..`/`x..=` The other // two variants are handled with `parse_prefix_range_expr` call above. + // (and `x...y`/`x...` until SNAP) let rhs = if self.is_at_start_of_range_notation_rhs() { Some(self.parse_assoc_expr_with(op.precedence() + 1, LhsExpr::NotYetParsed)?) @@ -2852,8 +2857,8 @@ impl<'a> Parser<'a> { let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs); self.mk_expr(span, aopexpr, ThinVec::new()) } - AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotDot => { - self.bug("As, Colon, DotDot or DotDotDot branch reached") + AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotEq => { + self.bug("AssocOp should have been handled by special case") } }; @@ -2949,17 +2954,22 @@ impl<'a> Parser<'a> { } } - /// Parse prefix-forms of range notation: `..expr`, `..`, `...expr` + /// Parse prefix-forms of range notation: `..expr`, `..`, `..=expr` (and `...expr` until SNAP) fn parse_prefix_range_expr(&mut self, already_parsed_attrs: Option>) -> PResult<'a, P> { - debug_assert!(self.token == token::DotDot || self.token == token::DotDotDot, - "parse_prefix_range_expr: token {:?} is not DotDot or DotDotDot", + // SNAP remove DotDotDot + debug_assert!([token::DotDot, token::DotDotDot, token::DotDotEq].contains(&self.token), + "parse_prefix_range_expr: token {:?} is not DotDot/DotDotDot/DotDotEq", self.token); let tok = self.token.clone(); let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; let lo = self.span; let mut hi = self.span; + // Warn about deprecated ... syntax (until SNAP) + if tok == token::DotDotDot { + self.warn_dotdoteq(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. @@ -3450,7 +3460,7 @@ impl<'a> Parser<'a> { fn parse_as_ident(&mut self) -> bool { self.look_ahead(1, |t| match *t { token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) | - token::DotDotDot | token::ModSep | token::Not => Some(false), + token::DotDotDot | token::DotDotEq | token::ModSep | token::Not => Some(false), // ensure slice patterns [a, b.., c] and [a, b, c..] don't go into the // range pattern branch token::DotDot => None, @@ -3544,11 +3554,12 @@ impl<'a> Parser<'a> { let mac = respan(lo.to(self.prev_span), Mac_ { path: path, tts: tts }); pat = PatKind::Mac(mac); } - token::DotDotDot | token::DotDot => { + token::DotDotDot | token::DotDotEq | token::DotDot => { let end_kind = match self.token { token::DotDot => RangeEnd::Excluded, - token::DotDotDot => RangeEnd::Included, - _ => panic!("can only parse `..` or `...` for ranges (checked above)"), + token::DotDotDot | token::DotDotEq => RangeEnd::Included, + _ => panic!("can only parse `..`/`...`/`..=` for ranges \ + (checked above)"), }; // Parse range let span = lo.to(self.prev_span); @@ -3590,6 +3601,9 @@ impl<'a> Parser<'a> { if self.eat(&token::DotDotDot) { let end = self.parse_pat_range_end()?; pat = PatKind::Range(begin, end, RangeEnd::Included); + } else if self.eat(&token::DotDotEq) { + let end = self.parse_pat_range_end()?; + pat = PatKind::Range(begin, end, RangeEnd::Included); } else if self.eat(&token::DotDot) { let end = self.parse_pat_range_end()?; pat = PatKind::Range(begin, end, RangeEnd::Excluded); @@ -3973,7 +3987,7 @@ impl<'a> Parser<'a> { token::BinOp(token::Minus) | token::BinOp(token::Star) | token::BinOp(token::And) | token::BinOp(token::Or) | token::AndAnd | token::OrOr | - token::DotDot | token::DotDotDot => false, + token::DotDot | token::DotDotDot | token::DotDotEq => false, _ => true, } { self.warn_missing_semicolon(); @@ -4195,6 +4209,12 @@ impl<'a> Parser<'a> { }).emit(); } + fn warn_dotdoteq(&self, span: Span) { + self.diagnostic().struct_span_warn(span, { + "`...` is being replaced by `..=`" + }).emit(); + } + // Parse bounds of a type parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. // BOUND = TY_BOUND | LT_BOUND // LT_BOUND = LIFETIME (e.g. `'a`) diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index a316733bdb5..4888654fac9 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -152,6 +152,8 @@ pub enum Token { Dot, DotDot, DotDotDot, + DotDotEq, + DotEq, // HACK(durka42) never produced by the parser, only used for libproc_macro Comma, Semi, Colon, @@ -212,18 +214,19 @@ impl Token { pub fn can_begin_expr(&self) -> bool { match *self { Ident(ident) => ident_can_begin_expr(ident), // value name or keyword - 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 + 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 | DotDotEq | // range notation + // SNAP remove DotDotDot + Lt | BinOp(Shl) | // associated path + ModSep | // global path + Pound => true, // expression attributes Interpolated(ref nt) => match nt.0 { NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) => true, _ => false, @@ -402,10 +405,12 @@ impl Token { Dot => match joint { Dot => DotDot, DotDot => DotDotDot, + DotEq => DotDotEq, _ => return None, }, DotDot => match joint { Dot => DotDotDot, + Eq => DotDotEq, _ => return None, }, Colon => match joint { @@ -413,9 +418,9 @@ impl Token { _ => return None, }, - Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | Comma | - Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | - OpenDelim(..) | CloseDelim(..) | Underscore => return None, + Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | DotEq | + DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | + Question | OpenDelim(..) | CloseDelim(..) | Underscore => return None, Literal(..) | Ident(..) | Lifetime(..) | Interpolated(..) | DocComment(..) | Whitespace | Comment | Shebang(..) | Eof => return None, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 9903dc50f36..cc4b34854fc 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -203,6 +203,8 @@ pub fn token_to_string(tok: &Token) -> String { token::Dot => ".".to_string(), token::DotDot => "..".to_string(), token::DotDotDot => "...".to_string(), + token::DotDotEq => "..=".to_string(), + token::DotEq => ".=".to_string(), token::Comma => ",".to_string(), token::Semi => ";".to_string(), token::Colon => ":".to_string(), diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs index a4f06cb1b45..590874806d7 100644 --- a/src/libsyntax/util/parser.rs +++ b/src/libsyntax/util/parser.rs @@ -62,8 +62,8 @@ pub enum AssocOp { As, /// `..` range DotDot, - /// `...` range - DotDotDot, + /// `..=` range + DotDotEq, /// `:` Colon, } @@ -105,7 +105,8 @@ impl AssocOp { Token::AndAnd => Some(LAnd), Token::OrOr => Some(LOr), Token::DotDot => Some(DotDot), - Token::DotDotDot => Some(DotDotDot), + Token::DotDotEq => Some(DotDotEq), + Token::DotDotDot => Some(DotDotEq), // remove this after SNAP Token::Colon => Some(Colon), _ if t.is_keyword(keywords::As) => Some(As), _ => None @@ -151,7 +152,7 @@ impl AssocOp { Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => 7, LAnd => 6, LOr => 5, - DotDot | DotDotDot => 4, + DotDot | DotDotEq => 4, Inplace => 3, Assign | AssignOp(_) => 2, } @@ -166,7 +167,7 @@ impl AssocOp { As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | LAnd | LOr | Colon => Fixity::Left, - DotDot | DotDotDot => Fixity::None + DotDot | DotDotEq => Fixity::None } } @@ -176,7 +177,7 @@ impl AssocOp { Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true, Inplace | Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | - DotDot | DotDotDot | Colon => false + DotDot | DotDotEq | Colon => false } } @@ -186,7 +187,7 @@ impl AssocOp { Assign | AssignOp(_) | Inplace => true, Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | - LOr | DotDot | DotDotDot | Colon => false + LOr | DotDot | DotDotEq | Colon => false } } @@ -211,7 +212,7 @@ impl AssocOp { BitOr => Some(BinOpKind::BitOr), LAnd => Some(BinOpKind::And), LOr => Some(BinOpKind::Or), - Inplace | Assign | AssignOp(_) | As | DotDot | DotDotDot | Colon => None + Inplace | Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None } } } diff --git a/src/test/compile-fail/E0586.rs b/src/test/compile-fail/E0586.rs index 0b063569abc..c1bfc5c73a1 100644 --- a/src/test/compile-fail/E0586.rs +++ b/src/test/compile-fail/E0586.rs @@ -10,5 +10,5 @@ fn main() { let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1]; - let x = &tmp[1...]; //~ ERROR E0586 + let x = &tmp[1..=]; //~ ERROR E0586 } diff --git a/src/test/compile-fail/impossible_range.rs b/src/test/compile-fail/impossible_range.rs index 94e048fed65..e4465e9f6b6 100644 --- a/src/test/compile-fail/impossible_range.rs +++ b/src/test/compile-fail/impossible_range.rs @@ -18,12 +18,12 @@ pub fn main() { ..1; 0..1; - ...; //~ERROR inclusive range with no end + ..=; //~ERROR inclusive range with no end //~^HELP bounded at the end - 0...; //~ERROR inclusive range with no end + 0..=; //~ERROR inclusive range with no end //~^HELP bounded at the end - ...1; - 0...1; + ..=1; + 0..=1; } diff --git a/src/test/compile-fail/range_inclusive_gate.rs b/src/test/compile-fail/range_inclusive_gate.rs index 1d1153e951b..69b9a4c67ad 100644 --- a/src/test/compile-fail/range_inclusive_gate.rs +++ b/src/test/compile-fail/range_inclusive_gate.rs @@ -14,7 +14,7 @@ // #![feature(inclusive_range)] pub fn main() { - let _: std::ops::RangeInclusive<_> = { use std::intrinsics; 1 } ... { use std::intrinsics; 2 }; + let _: std::ops::RangeInclusive<_> = { use std::intrinsics; 1 } ..= { use std::intrinsics; 2 }; //~^ ERROR use of unstable library feature 'inclusive_range' //~| ERROR core_intrinsics //~| ERROR core_intrinsics diff --git a/src/test/incremental/hashes/indexing_expressions.rs b/src/test/incremental/hashes/indexing_expressions.rs index bb31982d93f..a12624d0832 100644 --- a/src/test/incremental/hashes/indexing_expressions.rs +++ b/src/test/incremental/hashes/indexing_expressions.rs @@ -153,5 +153,5 @@ fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] { #[rustc_metadata_clean(cfg="cfail2")] #[rustc_metadata_clean(cfg="cfail3")] fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] { - &slice[3...7] + &slice[3..=7] } diff --git a/src/test/parse-fail/pat-ranges-1.rs b/src/test/parse-fail/pat-ranges-1.rs index e1cbb961b1b..857a3924aec 100644 --- a/src/test/parse-fail/pat-ranges-1.rs +++ b/src/test/parse-fail/pat-ranges-1.rs @@ -11,5 +11,5 @@ // Parsing of range patterns fn main() { - let macropus!() ... 11 = 12; //~ error: expected one of `:`, `;`, or `=`, found `...` + let macropus!() ..= 11 = 12; //~ error: expected one of `:`, `;`, or `=`, found `..=` } diff --git a/src/test/parse-fail/pat-ranges-2.rs b/src/test/parse-fail/pat-ranges-2.rs index 04ad5ff083b..64c749333cf 100644 --- a/src/test/parse-fail/pat-ranges-2.rs +++ b/src/test/parse-fail/pat-ranges-2.rs @@ -11,5 +11,5 @@ // Parsing of range patterns fn main() { - let 10 ... makropulos!() = 12; //~ error: expected one of `::`, `:`, `;`, or `=`, found `!` + let 10 ..= makropulos!() = 12; //~ error: expected one of `::`, `:`, `;`, or `=`, found `!` } diff --git a/src/test/parse-fail/pat-ranges-3.rs b/src/test/parse-fail/pat-ranges-3.rs index 5f7aac71d29..1327a9fab36 100644 --- a/src/test/parse-fail/pat-ranges-3.rs +++ b/src/test/parse-fail/pat-ranges-3.rs @@ -11,5 +11,5 @@ // Parsing of range patterns fn main() { - let 10 ... 10 + 3 = 12; //~ expected one of `:`, `;`, or `=`, found `+` + let 10 ..= 10 + 3 = 12; //~ expected one of `:`, `;`, or `=`, found `+` } diff --git a/src/test/parse-fail/pat-ranges-4.rs b/src/test/parse-fail/pat-ranges-4.rs index 4bbf387d1c0..c159c770250 100644 --- a/src/test/parse-fail/pat-ranges-4.rs +++ b/src/test/parse-fail/pat-ranges-4.rs @@ -11,5 +11,6 @@ // Parsing of range patterns fn main() { - let 10 - 3 ... 10 = 8; //~ error: expected one of `...`, `..`, `:`, `;`, or `=`, found `-` + let 10 - 3 ..= 10 = 8; + //~^ error: expected one of `...`, `..=`, `..`, `:`, `;`, or `=`, found `-` } diff --git a/src/test/parse-fail/range_inclusive.rs b/src/test/parse-fail/range_inclusive.rs index ce97372c668..cc32b9903b5 100644 --- a/src/test/parse-fail/range_inclusive.rs +++ b/src/test/parse-fail/range_inclusive.rs @@ -13,7 +13,7 @@ #![feature(inclusive_range_syntax, inclusive_range)] pub fn main() { - for _ in 1... {} //~ERROR inclusive range with no end + for _ in 1..= {} //~ERROR inclusive range with no end //~^HELP bounded at the end } diff --git a/src/test/parse-fail/range_inclusive_gate.rs b/src/test/parse-fail/range_inclusive_gate.rs index 30dc6fc5b20..de690c3fea3 100644 --- a/src/test/parse-fail/range_inclusive_gate.rs +++ b/src/test/parse-fail/range_inclusive_gate.rs @@ -15,21 +15,21 @@ // #![feature(inclusive_range_syntax, inclusive_range)] macro_rules! m { - () => { for _ in 1...10 {} } //~ ERROR inclusive range syntax is experimental + () => { for _ in 1..=10 {} } //~ ERROR inclusive range syntax is experimental } #[cfg(nope)] fn f() {} #[cfg(not(nope))] fn f() { - for _ in 1...10 {} //~ ERROR inclusive range syntax is experimental + for _ in 1..=10 {} //~ ERROR inclusive range syntax is experimental } #[cfg(nope)] macro_rules! n { () => {} } #[cfg(not(nope))] macro_rules! n { - () => { for _ in 1...10 {} } //~ ERROR inclusive range syntax is experimental + () => { for _ in 1..=10 {} } //~ ERROR inclusive range syntax is experimental } macro_rules! o { @@ -38,7 +38,7 @@ macro_rules! o { fn g() {} #[cfg(not(nope))] fn g() { - for _ in 1...10 {} //~ ERROR inclusive range syntax is experimental + for _ in 1..=10 {} //~ ERROR inclusive range syntax is experimental } g(); @@ -54,7 +54,7 @@ macro_rules! p { fn h() {} #[cfg(not(nope))] fn h() { - for _ in 1...10 {} //~ ERROR inclusive range syntax is experimental + for _ in 1..=10 {} //~ ERROR inclusive range syntax is experimental } h(); @@ -62,8 +62,8 @@ macro_rules! p { } pub fn main() { - for _ in 1...10 {} //~ ERROR inclusive range syntax is experimental - for _ in ...10 {} //~ ERROR inclusive range syntax is experimental + for _ in 1..=10 {} //~ ERROR inclusive range syntax is experimental + for _ in ..=10 {} //~ ERROR inclusive range syntax is experimental f(); // not allowed in cfg'ed functions diff --git a/src/test/run-pass/inc-range-pat.rs b/src/test/run-pass/inc-range-pat.rs new file mode 100644 index 00000000000..237b41b6128 --- /dev/null +++ b/src/test/run-pass/inc-range-pat.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. + +// Test old and new syntax for inclusive range patterns. + +fn main() { + assert!(match 42 { 0 ... 100 => true, _ => false }); + assert!(match 42 { 0 ..= 100 => true, _ => false }); + + assert!(match 'x' { 'a' ... 'z' => true, _ => false }); + assert!(match 'x' { 'a' ..= 'z' => true, _ => false }); +} + diff --git a/src/test/run-pass/range_inclusive.rs b/src/test/run-pass/range_inclusive.rs index f6119e70999..71e11804052 100644 --- a/src/test/run-pass/range_inclusive.rs +++ b/src/test/run-pass/range_inclusive.rs @@ -17,18 +17,18 @@ use std::ops::{RangeInclusive, RangeToInclusive}; fn foo() -> isize { 42 } // Test that range syntax works in return statements -fn return_range_to() -> RangeToInclusive { return ...1; } +fn return_range_to() -> RangeToInclusive { return ..=1; } pub fn main() { let mut count = 0; - for i in 0_usize...10 { + for i in 0_usize..=10 { assert!(i >= 0 && i <= 10); count += i; } assert_eq!(count, 55); let mut count = 0; - let mut range = 0_usize...10; + let mut range = 0_usize..=10; for i in range { assert!(i >= 0 && i <= 10); count += i; @@ -36,53 +36,53 @@ pub fn main() { assert_eq!(count, 55); let mut count = 0; - for i in (0_usize...10).step_by(2) { + for i in (0_usize..=10).step_by(2) { assert!(i >= 0 && i <= 10 && i % 2 == 0); count += i; } assert_eq!(count, 30); - let _ = 0_usize...4+4-3; - let _ = 0...foo(); + let _ = 0_usize..=4+4-3; + let _ = 0..=foo(); - let _ = { &42...&100 }; // references to literals are OK - let _ = ...42_usize; + let _ = { &42..=&100 }; // references to literals are OK + let _ = ..=42_usize; // Test we can use two different types with a common supertype. let x = &42; { let y = 42; - let _ = x...&y; + let _ = x..=&y; } // test collection indexing - let vec = (0...10).collect::>(); + let vec = (0..=10).collect::>(); let slice: &[_] = &*vec; let string = String::from("hello world"); let stir = "hello world"; - assert_eq!(&vec[3...6], &[3, 4, 5, 6]); - assert_eq!(&vec[ ...6], &[0, 1, 2, 3, 4, 5, 6]); + assert_eq!(&vec[3..=6], &[3, 4, 5, 6]); + assert_eq!(&vec[ ..=6], &[0, 1, 2, 3, 4, 5, 6]); - assert_eq!(&slice[3...6], &[3, 4, 5, 6]); - assert_eq!(&slice[ ...6], &[0, 1, 2, 3, 4, 5, 6]); + assert_eq!(&slice[3..=6], &[3, 4, 5, 6]); + assert_eq!(&slice[ ..=6], &[0, 1, 2, 3, 4, 5, 6]); - assert_eq!(&string[3...6], "lo w"); - assert_eq!(&string[ ...6], "hello w"); + assert_eq!(&string[3..=6], "lo w"); + assert_eq!(&string[ ..=6], "hello w"); - assert_eq!(&stir[3...6], "lo w"); - assert_eq!(&stir[ ...6], "hello w"); + assert_eq!(&stir[3..=6], "lo w"); + assert_eq!(&stir[ ..=6], "hello w"); // test the size hints and emptying - let mut long = 0...255u8; - let mut short = 42...42u8; + let mut long = 0..=255u8; + let mut short = 42..=42u8; assert_eq!(long.size_hint(), (256, Some(256))); assert_eq!(short.size_hint(), (1, Some(1))); long.next(); short.next(); assert_eq!(long.size_hint(), (255, Some(255))); assert_eq!(short.size_hint(), (0, Some(0))); - assert_eq!(short, 1...0); + assert_eq!(short, 1..=0); assert_eq!(long.len(), 255); assert_eq!(short.len(), 0); @@ -94,31 +94,31 @@ pub fn main() { assert_eq!(long.next(), Some(1)); assert_eq!(long.next(), Some(2)); assert_eq!(long.next_back(), Some(252)); - for i in 3...251 { + for i in 3..=251 { assert_eq!(long.next(), Some(i)); } - assert_eq!(long, 1...0); + assert_eq!(long, 1..=0); // check underflow - let mut narrow = 1...0; + let mut narrow = 1..=0; assert_eq!(narrow.next_back(), None); - assert_eq!(narrow, 1...0); - let mut zero = 0u8...0; + assert_eq!(narrow, 1..=0); + let mut zero = 0u8..=0; assert_eq!(zero.next_back(), Some(0)); assert_eq!(zero.next_back(), None); - assert_eq!(zero, 1...0); - let mut high = 255u8...255; + assert_eq!(zero, 1..=0); + let mut high = 255u8..=255; assert_eq!(high.next_back(), Some(255)); assert_eq!(high.next_back(), None); - assert_eq!(high, 1...0); + assert_eq!(high, 1..=0); // what happens if you have a nonsense range? - let mut nonsense = 10...5; + let mut nonsense = 10..=5; assert_eq!(nonsense.next(), None); - assert_eq!(nonsense, 10...5); + assert_eq!(nonsense, 10..=5); // output - assert_eq!(format!("{:?}", 0...10), "0...10"); - assert_eq!(format!("{:?}", ...10), "...10"); - assert_eq!(format!("{:?}", long), "1...0"); + assert_eq!(format!("{:?}", 0..=10), "0..=10"); + assert_eq!(format!("{:?}", ..=10), "..=10"); + assert_eq!(format!("{:?}", long), "1..=0"); } diff --git a/src/test/run-pass/range_inclusive_gate.rs b/src/test/run-pass/range_inclusive_gate.rs index 5e0ec19d6b3..570087aedbb 100644 --- a/src/test/run-pass/range_inclusive_gate.rs +++ b/src/test/run-pass/range_inclusive_gate.rs @@ -14,7 +14,7 @@ fn main() { let mut count = 0; - for i in 0_usize...10 { + for i in 0_usize..=10 { assert!(i >= 0 && i <= 10); count += i; } -- cgit 1.4.1-3-g733a5 From 7aabf572789dcae24cc8ce247f7d86bcc5d49a17 Mon Sep 17 00:00:00 2001 From: Badel2 <2badel2@gmail.com> Date: Thu, 21 Sep 2017 12:13:26 +0200 Subject: Add information about the syntax used in ranges ... or ..= --- src/librustc/hir/lowering.rs | 2 +- src/libsyntax/ast.rs | 10 ++++++++-- src/libsyntax/parse/parser.rs | 11 +++++++---- src/libsyntax/print/pprust.rs | 5 +++-- 4 files changed, 19 insertions(+), 9 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 465520ea034..6da8c38dfcf 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1869,7 +1869,7 @@ impl<'a> LoweringContext<'a> { fn lower_range_end(&mut self, e: &RangeEnd) -> hir::RangeEnd { match *e { - RangeEnd::Included => hir::RangeEnd::Included, + RangeEnd::Included(_) => hir::RangeEnd::Included, RangeEnd::Excluded => hir::RangeEnd::Excluded, } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 496be8b3eb2..0504e889ea1 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -538,10 +538,16 @@ pub enum BindingMode { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum RangeEnd { - Included, + Included(RangeSyntax), Excluded, } +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum RangeSyntax { + DotDotDot, + DotDotEq, +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum PatKind { /// Represents a wildcard pattern (`_`) @@ -578,7 +584,7 @@ pub enum PatKind { Ref(P, Mutability), /// A literal Lit(P), - /// A range pattern, e.g. `1...2` or `1..2` + /// A range pattern, e.g. `1...2`, `1..=2` or `1..2` Range(P, P, RangeEnd), /// `[a, b, ..i, y, z]` is represented as: /// `PatKind::Slice(box [a, b], Some(i), box [y, z])` diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 80c976abd19..bc78bfa785b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -38,7 +38,7 @@ use ast::{Ty, TyKind, TypeBinding, TyParam, TyParamBounds}; use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; use ast::{Visibility, WhereClause}; use ast::{BinOpKind, UnOp}; -use ast::RangeEnd; +use ast::{RangeEnd, RangeSyntax}; use {ast, attr}; use codemap::{self, CodeMap, Spanned, respan}; use syntax_pos::{self, Span, BytePos}; @@ -3557,7 +3557,8 @@ impl<'a> Parser<'a> { token::DotDotDot | token::DotDotEq | token::DotDot => { let end_kind = match self.token { token::DotDot => RangeEnd::Excluded, - token::DotDotDot | token::DotDotEq => RangeEnd::Included, + token::DotDotDot => RangeEnd::Included(RangeSyntax::DotDotDot), + token::DotDotEq => RangeEnd::Included(RangeSyntax::DotDotEq), _ => panic!("can only parse `..`/`...`/`..=` for ranges \ (checked above)"), }; @@ -3600,10 +3601,12 @@ impl<'a> Parser<'a> { Ok(begin) => { if self.eat(&token::DotDotDot) { let end = self.parse_pat_range_end()?; - pat = PatKind::Range(begin, end, RangeEnd::Included); + pat = PatKind::Range(begin, end, + RangeEnd::Included(RangeSyntax::DotDotDot)); } else if self.eat(&token::DotDotEq) { let end = self.parse_pat_range_end()?; - pat = PatKind::Range(begin, end, RangeEnd::Included); + pat = PatKind::Range(begin, end, + RangeEnd::Included(RangeSyntax::DotDotEq)); } else if self.eat(&token::DotDot) { let end = self.parse_pat_range_end()?; pat = PatKind::Range(begin, end, RangeEnd::Excluded); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index cc4b34854fc..959dd4ef30f 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -11,7 +11,7 @@ pub use self::AnnNode::*; use abi::{self, Abi}; -use ast::{self, BlockCheckMode, PatKind, RangeEnd}; +use ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax}; use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::Attribute; use util::parser::{self, AssocOp, Fixity}; @@ -2590,7 +2590,8 @@ impl<'a> State<'a> { self.print_expr(begin)?; self.s.space()?; match *end_kind { - RangeEnd::Included => self.s.word("...")?, + RangeEnd::Included(RangeSyntax::DotDotDot) => self.s.word("...")?, + RangeEnd::Included(RangeSyntax::DotDotEq) => self.s.word("..=")?, RangeEnd::Excluded => self.s.word("..")?, } self.print_expr(end)?; -- cgit 1.4.1-3-g733a5 From 54c4a830843d8de97d1dd3f936f9e3415bc96ef9 Mon Sep 17 00:00:00 2001 From: Badel2 <2badel2@gmail.com> Date: Thu, 21 Sep 2017 12:14:14 +0200 Subject: dotdoteq_in_patterns feature gate --- src/libsyntax/feature_gate.rs | 9 ++++++++- .../compile-fail/feature-gate-dotdoteq_in_patterns.rs | 16 ++++++++++++++++ src/test/run-pass/inc-range-pat.rs | 2 ++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/feature-gate-dotdoteq_in_patterns.rs (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 2fc451d5d00..aa5a4143027 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -26,7 +26,7 @@ use self::AttributeType::*; use self::AttributeGate::*; use abi::Abi; -use ast::{self, NodeId, PatKind, RangeEnd}; +use ast::{self, NodeId, PatKind, RangeEnd, RangeSyntax}; use attr; use codemap::Spanned; use syntax_pos::Span; @@ -392,6 +392,9 @@ declare_features! ( // allow `'_` placeholder lifetimes (active, underscore_lifetimes, "1.22.0", Some(44524)), + + // allow `..=` in patterns (RFC 1192) + (active, dotdoteq_in_patterns, "1.22.0", Some(28237)), ); declare_features! ( @@ -1491,6 +1494,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, exclusive_range_pattern, pattern.span, "exclusive range pattern syntax is experimental"); } + PatKind::Range(_, _, RangeEnd::Included(RangeSyntax::DotDotEq)) => { + gate_feature_post!(&self, dotdoteq_in_patterns, pattern.span, + "`..=` syntax in patterns is experimental"); + } _ => {} } visit::walk_pat(self, pattern) diff --git a/src/test/compile-fail/feature-gate-dotdoteq_in_patterns.rs b/src/test/compile-fail/feature-gate-dotdoteq_in_patterns.rs new file mode 100644 index 00000000000..1fb139bf07f --- /dev/null +++ b/src/test/compile-fail/feature-gate-dotdoteq_in_patterns.rs @@ -0,0 +1,16 @@ +// 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. + +pub fn main() { + match 22 { + 0 ..= 3 => {} //~ ERROR `..=` syntax in patterns is experimental + _ => {} + } +} diff --git a/src/test/run-pass/inc-range-pat.rs b/src/test/run-pass/inc-range-pat.rs index 237b41b6128..5faf36eddaf 100644 --- a/src/test/run-pass/inc-range-pat.rs +++ b/src/test/run-pass/inc-range-pat.rs @@ -9,6 +9,8 @@ // except according to those terms. // Test old and new syntax for inclusive range patterns. +#![feature(dotdoteq_in_patterns)] + fn main() { assert!(match 42 { 0 ... 100 => true, _ => false }); -- cgit 1.4.1-3-g733a5 From 8917616e6a295fb4080c8e29362dc1e5a477c479 Mon Sep 17 00:00:00 2001 From: "Zack M. Davis" Date: Fri, 22 Sep 2017 15:45:47 -0700 Subject: add comparison operators to must-use lint (under `fn_must_use` feature) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Although RFC 1940 is about annotating functions with `#[must_use]`, a key part of the motivation was linting unused equality operators. (See https://github.com/rust-lang/rfcs/pull/1812#issuecomment-265695898—it seems to have not been clear to discussants at the time that marking the comparison methods as `must_use` would not give us the lints on comparison operators, at least in (what the present author understood as) the most straightforward implementation, as landed in #43728 (3645b062).) To rectify the situation, we here lint unused comparison operators as part of the unused-must-use lint (feature gated by the `fn_must_use` feature flag, which now arguably becomes a slight (tolerable in the opinion of the present author) misnomer). This is in the matter of #43302. --- src/librustc_lint/unused.rs | 18 +++++++++++++++++- src/libsyntax/feature_gate.rs | 2 +- .../ui/rfc_1940-must_use_on_functions/fn_must_use.rs | 7 +++---- .../rfc_1940-must_use_on_functions/fn_must_use.stderr | 8 +++++++- 4 files changed, 28 insertions(+), 7 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 439cc3a4b84..b97920dd18b 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -153,6 +153,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { }; let mut fn_warned = false; + let mut op_warned = false; if cx.tcx.sess.features.borrow().fn_must_use { let maybe_def = match expr.node { hir::ExprCall(ref callee, _) => { @@ -172,9 +173,24 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { let def_id = def.def_id(); fn_warned = check_must_use(cx, def_id, s.span, "return value of "); } + + if let hir::ExprBinary(bin_op, ..) = expr.node { + match bin_op.node { + // Hardcoding the comparison operators here seemed more + // expedient than the refactoring that would be needed to + // look up the `#[must_use]` attribute which does exist on + // the comparison trait methods + hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => { + let msg = "unused comparison which must be used"; + cx.span_lint(UNUSED_MUST_USE, expr.span, msg); + op_warned = true; + }, + _ => {}, + } + } } - if !(ty_warned || fn_warned) { + if !(ty_warned || fn_warned || op_warned) { cx.span_lint(UNUSED_RESULTS, s.span, "unused result"); } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1fef382c83a..5c730aaa8d0 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -380,7 +380,7 @@ declare_features! ( // #[doc(masked)] (active, doc_masked, "1.21.0", None), - // allow `#[must_use]` on functions (RFC 1940) + // allow `#[must_use]` on functions and comparison operators (RFC 1940) (active, fn_must_use, "1.21.0", Some(43302)), // allow '|' at beginning of match arms (RFC 1925) diff --git a/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.rs b/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.rs index 7eb4c32972a..821cd30c8df 100644 --- a/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.rs +++ b/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.rs @@ -61,10 +61,9 @@ fn main() { m.need_to_use_this_method_value(); m.is_even(); // trait method! - m.replace(3); + m.replace(3); // won't warn (annotation needs to be in trait definition) - 2.eq(&3); + 2.eq(&3); // comparison methods are `must_use` - // FIXME: operators should probably be `must_use` if underlying method is - 2 == 3; + 2 == 3; // lint includes comparison operators } diff --git a/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.stderr b/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.stderr index 69755c89b48..7fc0a4ce1ed 100644 --- a/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.stderr +++ b/src/test/ui/rfc_1940-must_use_on_functions/fn_must_use.stderr @@ -25,6 +25,12 @@ warning: unused return value of `EvenNature::is_even` which must be used: no sid warning: unused return value of `std::cmp::PartialEq::eq` which must be used --> $DIR/fn_must_use.rs:66:5 | -66 | 2.eq(&3); +66 | 2.eq(&3); // comparison methods are `must_use` | ^^^^^^^^^ +warning: unused comparison which must be used + --> $DIR/fn_must_use.rs:68:5 + | +68 | 2 == 3; // lint includes comparison operators + | ^^^^^^ + -- cgit 1.4.1-3-g733a5 From 375332c6b9e70427cf12ede3af447ce285266892 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 21 Sep 2017 00:20:56 -0700 Subject: Fix bug in collecting trait and impl items with derives. --- src/libsyntax/ext/expand.rs | 8 +------- src/test/compile-fail/issue-43023.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 src/test/compile-fail/issue-43023.rs (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 5deb4c3cc00..68ddfdc404a 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -774,13 +774,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { item: Annotatable, kind: ExpansionKind) -> Expansion { - if !traits.is_empty() && - (kind == ExpansionKind::TraitItems || kind == ExpansionKind::ImplItems) { - self.cx.span_err(traits[0].span, "`derive` can be only be applied to items"); - self.cx.trace_macros_diag(); - return kind.expect_from_annotatables(::std::iter::once(item)); - } - self.collect(kind, InvocationKind::Attr { attr: attr, traits: traits, item: item }) + self.collect(kind, InvocationKind::Attr { attr, traits, item }) } // If `item` is an attr invocation, remove and return the macro attribute. diff --git a/src/test/compile-fail/issue-43023.rs b/src/test/compile-fail/issue-43023.rs new file mode 100644 index 00000000000..6a5f7a1136a --- /dev/null +++ b/src/test/compile-fail/issue-43023.rs @@ -0,0 +1,28 @@ +// 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 { + #[derive(Debug)] //~ ERROR `derive` may only be applied to structs, enums and unions + fn f() { + file!(); + } +} + +trait Tr1 { + #[derive(Debug)] //~ ERROR `derive` may only be applied to structs, enums and unions + fn f(); +} + +trait Tr2 { + #[derive(Debug)] //~ ERROR `derive` may only be applied to structs, enums and unions + type F; +} -- cgit 1.4.1-3-g733a5 From 3730dfdaf58057466a2c576184c4647840daaeac Mon Sep 17 00:00:00 2001 From: Matthias Devlamynck Date: Tue, 26 Sep 2017 11:43:33 +0200 Subject: impl Trait in argument position desugaring: Add a flag to hir and ty TypeParameterDef and raise an error when using explicit type parameters when calling a function using impl Trait in argument position. --- src/librustc/hir/lowering.rs | 4 ++++ src/librustc/hir/mod.rs | 8 +++++++ src/librustc/ich/impls_hir.rs | 7 +++++- src/librustc/ich/impls_ty.rs | 3 ++- src/librustc/ty/mod.rs | 2 ++ src/librustc_typeck/check/mod.rs | 31 ++++++++++++++++++++++++++ src/librustc_typeck/collect.rs | 3 +++ src/librustc_typeck/diagnostics.rs | 2 ++ src/libsyntax/feature_gate.rs | 6 +++++ src/test/compile-fail/synthetic-param.rs | 38 ++++++++++++++++++++++++++++++++ 10 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/synthetic-param.rs (limited to 'src/libsyntax') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 95b8e49d60c..769f1cbcb5d 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1103,6 +1103,10 @@ impl<'a> LoweringContext<'a> { default: tp.default.as_ref().map(|x| self.lower_ty(x)), span: tp.span, pure_wrt_drop: tp.attrs.iter().any(|attr| attr.check_name("may_dangle")), + synthetic: tp.attrs.iter() + .filter(|attr| attr.check_name("rustc_synthetic")) + .map(|_| hir::SyntheticTyParamKind::ImplTrait) + .nth(0), } } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index bff71155440..9bfedd7a381 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -351,6 +351,7 @@ pub struct TyParam { pub default: Option>, pub span: Span, pub pure_wrt_drop: bool, + pub synthetic: Option, } /// Represents lifetimes and type parameters attached to a declaration @@ -419,6 +420,13 @@ impl Generics { } } +/// Synthetic Type Parameters are converted to an other form during lowering, this allows +/// to track the original form they had. Usefull for error messages. +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum SyntheticTyParamKind { + ImplTrait +} + /// A `where` clause in a definition #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct WhereClause { diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 96d5940caf6..776f85cf5da 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -177,7 +177,8 @@ impl_stable_hash_for!(struct hir::TyParam { bounds, default, span, - pure_wrt_drop + pure_wrt_drop, + synthetic }); impl_stable_hash_for!(struct hir::Generics { @@ -187,6 +188,10 @@ impl_stable_hash_for!(struct hir::Generics { span }); +impl_stable_hash_for!(enum hir::SyntheticTyParamKind { + ImplTrait +}); + impl_stable_hash_for!(struct hir::WhereClause { id, predicates diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 2bbf807807b..fe060aaf426 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -463,7 +463,8 @@ impl_stable_hash_for!(struct ty::TypeParameterDef { index, has_default, object_lifetime_default, - pure_wrt_drop + pure_wrt_drop, + synthetic }); impl<'gcx, T> HashStable> diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 2c1b3e28ffb..da635ec80fc 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -675,6 +675,8 @@ pub struct TypeParameterDef { /// on generic parameter `T`, asserts data behind the parameter /// `T` won't be accessed during the parent type's `Drop` impl. pub pure_wrt_drop: bool, + + pub synthetic: Option, } #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6fe49644fe8..a06f7b7f63b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4647,6 +4647,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // a problem. self.check_path_parameter_count(span, &mut type_segment, false); self.check_path_parameter_count(span, &mut fn_segment, false); + self.check_impl_trait(span, &mut fn_segment); let (fn_start, has_self) = match (type_segment, fn_segment) { (_, Some((_, generics))) => { @@ -4871,6 +4872,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + /// Report error if there is an explicit type parameter when using `impl Trait`. + fn check_impl_trait(&self, + span: Span, + segment: &mut Option<(&hir::PathSegment, &ty::Generics)>) { + use hir::SyntheticTyParamKind::*; + + segment.map(|(path_segment, generics)| { + let explicit = !path_segment.infer_types; + let impl_trait = generics.types.iter() + .any(|ty_param| { + match ty_param.synthetic { + Some(ImplTrait) => true, + _ => false, + } + }); + + if explicit && impl_trait { + let mut err = struct_span_err! { + self.tcx.sess, + span, + E0631, + "cannot provide explicit type parameters when `impl Trait` is \ + used in argument position." + }; + + err.emit(); + } + }); + } + fn structurally_resolve_type_or_else(&self, sp: Span, ty: Ty<'tcx>, f: F) -> Ty<'tcx> where F: Fn() -> Ty<'tcx> diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a36594cb6e5..229a1084b0c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -922,6 +922,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, has_default: false, object_lifetime_default: rl::Set1::Empty, pure_wrt_drop: false, + synthetic: None, }); allow_defaults = true; @@ -993,6 +994,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, object_lifetime_default: object_lifetime_defaults.as_ref().map_or(rl::Set1::Empty, |o| o[i]), pure_wrt_drop: p.pure_wrt_drop, + synthetic: p.synthetic, } }); let mut types: Vec<_> = opt_self.into_iter().chain(types).collect(); @@ -1009,6 +1011,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, has_default: false, object_lifetime_default: rl::Set1::Empty, pure_wrt_drop: false, + synthetic: None, })); }); } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 6bbe2233ff1..4ad1697136a 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4677,4 +4677,6 @@ register_diagnostics! { E0592, // duplicate definitions with name `{}` // E0613, // Removed (merged with E0609) E0627, // yield statement outside of generator literal + E0631, // cannot provide explicit type parameters when `impl Trait` is used in + // argument position. } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 5c730aaa8d0..246300a24a9 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -724,6 +724,12 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), + ("rustc_synthetic", Whitelisted, Gated(Stability::Unstable, + "rustc_attrs", + "this attribute \ + is just used for rustc unit tests \ + and will never be stable", + cfg_fn!(rustc_attrs))), ("rustc_symbol_name", Whitelisted, Gated(Stability::Unstable, "rustc_attrs", "internal rustc attributes will never be stable", diff --git a/src/test/compile-fail/synthetic-param.rs b/src/test/compile-fail/synthetic-param.rs new file mode 100644 index 00000000000..a9762e383fe --- /dev/null +++ b/src/test/compile-fail/synthetic-param.rs @@ -0,0 +1,38 @@ +// 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(generic_param_attrs, rustc_attrs)] + +fn func<#[rustc_synthetic] T>(_: T) {} + +struct Foo; + +impl Foo { + pub fn func<#[rustc_synthetic] T>(_: T) {} +} + +struct Bar { + t: S +} + +impl Bar { + pub fn func<#[rustc_synthetic] T>(_: T) {} +} + +fn main() { + func::(42); //~ ERROR cannot provide explicit type parameters + func(42); // Ok + + Foo::func::(42); //~ ERROR cannot provide explicit type parameters + Foo::func(42); // Ok + + Bar::::func::(42); //~ ERROR cannot provide explicit type parameters + Bar::::func(42); // Ok +} -- cgit 1.4.1-3-g733a5 From 0f97b6b73c647604ad08e475b68058f52c4951c4 Mon Sep 17 00:00:00 2001 From: Tomas Nilsson Date: Tue, 12 Sep 2017 21:55:41 +0200 Subject: Apply attr proc macros before cfg processing Now items are not fully configured until right before expanding derives. --- src/libsyntax/ext/expand.rs | 39 ++++++++++++++-------- src/test/run-pass-fulldeps/proc-macro/attr-cfg.rs | 39 ++++++++++++++++++++++ .../proc-macro/auxiliary/attr-cfg.rs | 32 ++++++++++++++++++ .../proc-macro/auxiliary/derive-attr-cfg.rs | 23 +++++++++++++ .../proc-macro/derive-attr-cfg.rs | 27 +++++++++++++++ 5 files changed, 146 insertions(+), 14 deletions(-) create mode 100644 src/test/run-pass-fulldeps/proc-macro/attr-cfg.rs create mode 100644 src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-cfg.rs create mode 100644 src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-attr-cfg.rs create mode 100644 src/test/run-pass-fulldeps/proc-macro/derive-attr-cfg.rs (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 68ddfdc404a..6e7a8203b61 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -308,7 +308,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { err.emit(); } - let item = item + let item = self.fully_configure(item) .map_attrs(|mut attrs| { attrs.retain(|a| a.path != "derive"); attrs }); let item_with_markers = add_derived_markers(&mut self.cx, item.span(), &traits, item.clone()); @@ -400,6 +400,27 @@ impl<'a, 'b> MacroExpander<'a, 'b> { result } + fn fully_configure(&mut self, item: Annotatable) -> Annotatable { + let mut cfg = StripUnconfigured { + should_test: self.cx.ecfg.should_test, + sess: self.cx.parse_sess, + features: self.cx.ecfg.features, + }; + // Since the item itself has already been configured by the InvocationCollector, + // we know that fold result vector will contain exactly one element + match item { + Annotatable::Item(item) => { + Annotatable::Item(cfg.fold_item(item).pop().unwrap()) + } + Annotatable::TraitItem(item) => { + Annotatable::TraitItem(item.map(|item| cfg.fold_trait_item(item).pop().unwrap())) + } + Annotatable::ImplItem(item) => { + Annotatable::ImplItem(item.map(|item| cfg.fold_impl_item(item).pop().unwrap())) + } + } + } + fn expand_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { let result = match invoc.kind { InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext), @@ -740,15 +761,6 @@ struct InvocationCollector<'a, 'b: 'a> { monotonic: bool, } -macro_rules! fully_configure { - ($this:ident, $node:ident, $noop_fold:ident) => { - match $noop_fold($node, &mut $this.cfg).pop() { - Some(node) => node, - None => return SmallVector::new(), - } - } -} - impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect(&mut self, expansion_kind: ExpansionKind, kind: InvocationKind) -> Expansion { let mark = Mark::fresh(self.cx.current_expansion.mark); @@ -900,7 +912,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { let (attr, traits, mut item) = self.classify_item(item); if attr.is_some() || !traits.is_empty() { - let item = Annotatable::Item(fully_configure!(self, item, noop_fold_item)); + let item = Annotatable::Item(item); return self.collect_attr(attr, traits, item, ExpansionKind::Items).make_items(); } @@ -974,8 +986,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { let (attr, traits, item) = self.classify_item(item); if attr.is_some() || !traits.is_empty() { - let item = - Annotatable::TraitItem(P(fully_configure!(self, item, noop_fold_trait_item))); + let item = Annotatable::TraitItem(P(item)); return self.collect_attr(attr, traits, item, ExpansionKind::TraitItems) .make_trait_items() } @@ -995,7 +1006,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { let (attr, traits, item) = self.classify_item(item); if attr.is_some() || !traits.is_empty() { - let item = Annotatable::ImplItem(P(fully_configure!(self, item, noop_fold_impl_item))); + let item = Annotatable::ImplItem(P(item)); return self.collect_attr(attr, traits, item, ExpansionKind::ImplItems) .make_impl_items(); } diff --git a/src/test/run-pass-fulldeps/proc-macro/attr-cfg.rs b/src/test/run-pass-fulldeps/proc-macro/attr-cfg.rs new file mode 100644 index 00000000000..5a28d756df5 --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/attr-cfg.rs @@ -0,0 +1,39 @@ +// 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. + +// aux-build:attr-cfg.rs +// ignore-stage1 +// revisions: foo bar + +#![feature(proc_macro)] + +extern crate attr_cfg; +use attr_cfg::attr_cfg; + +#[attr_cfg] +fn outer() -> u8 { + #[cfg(foo)] + fn inner() -> u8 { 1 } + + #[cfg(bar)] + fn inner() -> u8 { 2 } + + inner() +} + +#[cfg(foo)] +fn main() { + assert_eq!(outer(), 1); +} + +#[cfg(bar)] +fn main() { + assert_eq!(outer(), 2); +} diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-cfg.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-cfg.rs new file mode 100644 index 00000000000..9145c46cfc7 --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-cfg.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. + +// no-prefer-dynamic +#![feature(proc_macro)] +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn attr_cfg(args: TokenStream, input: TokenStream) -> TokenStream { + let input_str = input.to_string(); + + assert_eq!(input_str, "fn outer() -> u8 { + #[cfg(foo)] + fn inner() -> u8 { 1 } + #[cfg(bar)] + fn inner() -> u8 { 2 } + inner() +}"); + + input +} diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-attr-cfg.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-attr-cfg.rs new file mode 100644 index 00000000000..787a4a470e2 --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-attr-cfg.rs @@ -0,0 +1,23 @@ +// 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. + +// no-prefer-dynamic +#![feature(proc_macro)] +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_derive(Foo, attributes(foo))] +pub fn derive(input: TokenStream) -> TokenStream { + assert!(!input.to_string().contains("#[cfg(any())]")); + "".parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/proc-macro/derive-attr-cfg.rs b/src/test/run-pass-fulldeps/proc-macro/derive-attr-cfg.rs new file mode 100644 index 00000000000..b94c45248da --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/derive-attr-cfg.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. + +// aux-build:derive-attr-cfg.rs +// ignore-stage1 + +#![feature(proc_macro)] + +extern crate derive_attr_cfg; +use derive_attr_cfg::Foo; + +#[derive(Foo)] +#[foo] +struct S { + #[cfg(any())] + x: i32 +} + +fn main() { +} -- cgit 1.4.1-3-g733a5