From 0685e7a185d8687f2886af72b63965cbfdc2525e Mon Sep 17 00:00:00 2001 From: Alexander Bliskovsky Date: Mon, 23 Feb 2015 16:06:49 -0500 Subject: [PATCH 01/25] Added section on `cargo new` to "Hello Cargo!" chapter. --- src/doc/trpl/hello-cargo.md | 60 ++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/src/doc/trpl/hello-cargo.md b/src/doc/trpl/hello-cargo.md index 5eb6cd7c5cd..de2ce2d9ede 100644 --- a/src/doc/trpl/hello-cargo.md +++ b/src/doc/trpl/hello-cargo.md @@ -18,6 +18,8 @@ the Cargo README](https://github.com/rust-lang/cargo#installing-cargo-from-nightlies) for specific instructions about installing it. +## Converting to Cargo + Let's convert Hello World to Cargo. To Cargo-ify our project, we need to do two things: Make a `Cargo.toml` @@ -103,6 +105,62 @@ That's it! We've successfully built `hello_world` with Cargo. Even though our program is simple, it's using much of the real tooling that you'll use for the rest of your Rust career. +## A New Project + +You don't have to go through this whole process every time you want to start a new +project! Cargo has the ability to make a bare-bones project directory in which you +can start developing right away. + +To start a new project with Cargo, use `cargo new`: + +```{bash} +$ cargo new hello_world --bin +``` + +We're passing `--bin` because we're making a binary program: if we +were making a library, we'd leave it off. + +Let's check out what Cargo has generated for us: + +```{bash} +$ cd hello_world +$ tree . +. +├── Cargo.toml +└── src + └── main.rs + +1 directory, 2 files +``` + +If you don't have the `tree` command, you can probably get it from your distro's package +manager. It's not necessary, but it's certainly useful. + +This is all we need to get started. First, let's check out `Cargo.toml`: + +```{toml} +[package] + +name = "hello_world" +version = "0.0.1" +authors = ["Your Name "] +``` + +Cargo has populated this file with reasonable defaults based off the arguments +you gave it and your Git global config. You may notice that Cargo has also initialized +the `hello_world` directory as a Git repository. + +Here's what's in `src/main.rs`: + +```{rust} +fn main() { + println!("Hello, world!"); +} +``` + +Cargo has generated a "Hello World!" for us, and you're ready to start coding! A +much more in-depth guide to Cargo can be found [here](http://doc.crates.io/guide.html). + Now that you've got the tools down, let's actually learn more about the Rust language itself. These are the basics that will serve you well through the rest -of your time with Rust. +of your time with Rust. \ No newline at end of file From f49fd40f208827798ccd91394e3a3986c8bc6886 Mon Sep 17 00:00:00 2001 From: Alexander Bliskovsky Date: Mon, 23 Feb 2015 16:35:47 -0500 Subject: [PATCH 02/25] Removed `{}` and small wording fixes to "Hello Cargo!" chapter. --- src/doc/trpl/hello-cargo.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/doc/trpl/hello-cargo.md b/src/doc/trpl/hello-cargo.md index de2ce2d9ede..587da69d4a6 100644 --- a/src/doc/trpl/hello-cargo.md +++ b/src/doc/trpl/hello-cargo.md @@ -26,7 +26,7 @@ To Cargo-ify our project, we need to do two things: Make a `Cargo.toml` configuration file, and put our source file in the right place. Let's do that part first: -```{bash} +```bash $ mkdir src $ mv main.rs src/main.rs ``` @@ -38,7 +38,7 @@ place for everything, and everything in its place. Next, our configuration file: -```{bash} +```bash $ editor Cargo.toml ``` @@ -75,7 +75,7 @@ well as what it is named. Once you have this file in place, we should be ready to build! Try this: -```{bash} +```bash $ cargo build Compiling hello_world v0.0.1 (file:///home/yourname/projects/hello_world) $ ./target/hello_world @@ -113,7 +113,7 @@ can start developing right away. To start a new project with Cargo, use `cargo new`: -```{bash} +```bash $ cargo new hello_world --bin ``` @@ -122,7 +122,7 @@ were making a library, we'd leave it off. Let's check out what Cargo has generated for us: -```{bash} +```bash $ cd hello_world $ tree . . @@ -138,7 +138,7 @@ manager. It's not necessary, but it's certainly useful. This is all we need to get started. First, let's check out `Cargo.toml`: -```{toml} +```toml [package] name = "hello_world" @@ -146,13 +146,13 @@ version = "0.0.1" authors = ["Your Name "] ``` -Cargo has populated this file with reasonable defaults based off the arguments -you gave it and your Git global config. You may notice that Cargo has also initialized -the `hello_world` directory as a Git repository. +Cargo has populated this file with reasonable defaults based off the arguments you gave +it and your `git` global configuration. You may notice that Cargo has also initialized +the `hello_world` directory as a `git` repository. Here's what's in `src/main.rs`: -```{rust} +```rust fn main() { println!("Hello, world!"); } From 18878b155ebf3c70445f2a461582475f5ef72c92 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 24 Feb 2015 21:52:27 -0800 Subject: [PATCH 03/25] std: Require `&mut self` for Iterator::all Keeps the method consistent with `Iterator::any`. Closes #22617 [breaking-change] --- src/libcore/iter.rs | 4 ++-- src/librustc/middle/ty.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 48ec1342971..f82538e0b2a 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -637,8 +637,8 @@ pub trait IteratorExt: Iterator + Sized { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn all(self, mut f: F) -> bool where F: FnMut(Self::Item) -> bool { - for x in self { if !f(x) { return false; } } + fn all(&mut self, mut f: F) -> bool where F: FnMut(Self::Item) -> bool { + for x in self.by_ref() { if !f(x) { return false; } } true } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 91313633397..fbb4460f281 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3883,7 +3883,7 @@ pub fn is_type_representable<'tcx>(cx: &ctxt<'tcx>, sp: Span, ty: Ty<'tcx>) let types_a = substs_a.types.get_slice(subst::TypeSpace); let types_b = substs_b.types.get_slice(subst::TypeSpace); - let pairs = types_a.iter().zip(types_b.iter()); + let mut pairs = types_a.iter().zip(types_b.iter()); pairs.all(|(&a, &b)| same_type(a, b)) } From 7074346e4f092064c5a5fa276be81d08951f56c9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 25 Feb 2015 12:21:15 -0500 Subject: [PATCH 04/25] Change MarkerTrait to be invariant. This is a (small) loss of expressiveness, but is necessary for now to work around #22806. Fixes #22655. --- src/libcore/marker.rs | 8 ++++++- src/test/run-pass/traits-issue-22655.rs | 29 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/traits-issue-22655.rs diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 6c934a998de..868a671b956 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -275,7 +275,13 @@ macro_rules! impls{ /// any methods, but instead is used to gate access to data. /// /// FIXME. Better documentation needed here! -pub trait MarkerTrait : PhantomFn { } +pub trait MarkerTrait : PhantomFn { } +// ~~~~~ <-- FIXME(#22806)? +// +// Marker trait has been made invariant so as to avoid inf recursion, +// but we should ideally solve the underlying problem. That's a bit +// complicated. + impl MarkerTrait for T { } /// `PhantomFn` is a marker trait for use with traits that contain diff --git a/src/test/run-pass/traits-issue-22655.rs b/src/test/run-pass/traits-issue-22655.rs new file mode 100644 index 00000000000..18c7cfb0850 --- /dev/null +++ b/src/test/run-pass/traits-issue-22655.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. + +// Regression test for issue #22655: This test should not lead to +// infinite recursion. + +unsafe impl Send for Unique { } + +pub struct Unique { + pointer: *const T, +} + +pub struct Node { + vals: V, + edges: Unique>, +} + +fn is_send() {} + +fn main() { + is_send::>(); +} From 07dc8d67c92017f950eef3951ec901cb2a3add7e Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Wed, 25 Feb 2015 13:37:22 -0500 Subject: [PATCH 05/25] Result::or : avoid over-specializing the type Changes .or() so that it can return a Result with a different E type than the one it is called on. Essentially: fn or(self, res: Result) -> Result becomes fn or(self, res: Result) -> Result This brings `or` in line with the existing `and` and `or_else` member types. This is a [breaking-change] Due to some code needing additional type annotations. --- src/libcore/result.rs | 4 ++-- src/libcoretest/result.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 23e936a75d7..ec0c19d36e4 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -641,9 +641,9 @@ impl Result { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn or(self, res: Result) -> Result { + pub fn or(self, res: Result) -> Result { match self { - Ok(_) => self, + Ok(v) => Ok(v), Err(_) => res, } } diff --git a/src/libcoretest/result.rs b/src/libcoretest/result.rs index ab7b5101e72..10cc3ad6424 100644 --- a/src/libcoretest/result.rs +++ b/src/libcoretest/result.rs @@ -36,10 +36,10 @@ pub fn test_and_then() { #[test] pub fn test_or() { - assert_eq!(op1().or(Ok(667)).unwrap(), 666); + assert_eq!(op1().or(Ok::<_, &'static str>(667)).unwrap(), 666); assert_eq!(op1().or(Err("bad")).unwrap(), 666); - assert_eq!(op2().or(Ok(667)).unwrap(), 667); + assert_eq!(op2().or(Ok::<_, &'static str>(667)).unwrap(), 667); assert_eq!(op2().or(Err("bad")).unwrap_err(), "bad"); } From 5dd001b2fc06526222c89a8563b25e4850646c15 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Mon, 23 Feb 2015 22:47:56 -0800 Subject: [PATCH 06/25] Fix overflow in precise_time_ns() on Windows, which starts happening after ~2 hours of machine uptime. --- src/libstd/sys/windows/time.rs | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs index 20ceff0aa69..209460df10b 100644 --- a/src/libstd/sys/windows/time.rs +++ b/src/libstd/sys/windows/time.rs @@ -12,6 +12,8 @@ use ops::Sub; use time::Duration; use sync::{Once, ONCE_INIT}; +const NANOS_PER_SEC: i64 = 1_000_000_000; + pub struct SteadyTime { t: libc::LARGE_INTEGER, } @@ -24,7 +26,7 @@ impl SteadyTime { } pub fn ns(&self) -> u64 { - self.t as u64 * 1_000_000_000 / frequency() as u64 + mul_div_i64(self.t as i64, NANOS_PER_SEC, frequency() as i64) as u64 } } @@ -45,6 +47,27 @@ impl<'a> Sub for &'a SteadyTime { fn sub(self, other: &SteadyTime) -> Duration { let diff = self.t as i64 - other.t as i64; - Duration::microseconds(diff * 1_000_000 / frequency() as i64) + Duration::nanoseconds(mul_div_i64(diff, NANOS_PER_SEC, frequency() as i64)) } } + +// Computes (value*numer)/denom without overflow, as long as both +// (numer*denom) and the overall result fit into i64 (which is the case +// for our time conversions). +fn mul_div_i64(value: i64, numer: i64, denom: i64) -> i64 { + let q = value / denom; + let r = value % denom; + // Decompose value as (value/denom*denom + value%denom), + // substitute into (value*numer)/denom and simplify. + // r < denom, so (denom*numer) is the upper bound of (r*numer) + q * numer + r * numer / denom +} + +#[test] +fn test_muldiv() { + assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000, 1_000_000), 1_000_000_000_001_000); + assert_eq!(mul_div_i64(-1_000_000_000_001, 1_000_000_000, 1_000_000), -1_000_000_000_001_000); + assert_eq!(mul_div_i64(-1_000_000_000_001,-1_000_000_000, 1_000_000), 1_000_000_000_001_000); + assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000,-1_000_000), -1_000_000_000_001_000); + assert_eq!(mul_div_i64( 1_000_000_000_001,-1_000_000_000,-1_000_000), 1_000_000_000_001_000); +} From 65ea9110bd930dc74b0fc37bf151dbbce80fe4ee Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Wed, 25 Feb 2015 17:11:36 -0800 Subject: [PATCH 07/25] Always error on invalid macro fragment specifiers Fixes #21370. unused-macro-with-follow-violation.rs was already handled correctly. That test is just for good measure. :) --- src/libsyntax/ext/tt/macro_rules.rs | 8 ++++---- .../unused-macro-with-bad-frag-spec.rs | 17 +++++++++++++++++ .../unused-macro-with-follow-violation.rs | 15 +++++++++++++++ 3 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 src/test/compile-fail/unused-macro-with-bad-frag-spec.rs create mode 100644 src/test/compile-fail/unused-macro-with-follow-violation.rs diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index fa6d934a457..67011ad21a6 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -334,6 +334,10 @@ fn check_matcher<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token) let tok = if let TtToken(_, ref tok) = *token { tok } else { unreachable!() }; // If T' is in the set FOLLOW(NT), continue. Else, reject. match (&next_token, is_in_follow(cx, &next_token, frag_spec.as_str())) { + (_, Err(msg)) => { + cx.span_err(sp, &msg); + continue + } (&Eof, _) => return Some((sp, tok.clone())), (_, Ok(true)) => continue, (next, Ok(false)) => { @@ -343,10 +347,6 @@ fn check_matcher<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token) token_to_string(next))); continue }, - (_, Err(msg)) => { - cx.span_err(sp, &msg); - continue - } } }, TtSequence(sp, ref seq) => { diff --git a/src/test/compile-fail/unused-macro-with-bad-frag-spec.rs b/src/test/compile-fail/unused-macro-with-bad-frag-spec.rs new file mode 100644 index 00000000000..b868b79365d --- /dev/null +++ b/src/test/compile-fail/unused-macro-with-bad-frag-spec.rs @@ -0,0 +1,17 @@ +// 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. + +// Issue #21370 + +macro_rules! test { + ($wrong:t_ty) => () //~ ERROR invalid fragment specifier `t_ty` +} + +fn main() { } diff --git a/src/test/compile-fail/unused-macro-with-follow-violation.rs b/src/test/compile-fail/unused-macro-with-follow-violation.rs new file mode 100644 index 00000000000..e9d09bb6ad9 --- /dev/null +++ b/src/test/compile-fail/unused-macro-with-follow-violation.rs @@ -0,0 +1,15 @@ +// 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. + +macro_rules! test { + ($e:expr +) => () //~ ERROR not allowed for `expr` fragments +} + +fn main() { } From 65b0655230085d7f6400e0d0c21292053e41adc1 Mon Sep 17 00:00:00 2001 From: Alexander Bliskovsky Date: Tue, 24 Feb 2015 00:13:04 -0500 Subject: [PATCH 08/25] Added documentation of backslash ending string literals. Closes #22698 --- src/doc/reference.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index 781b40be768..81e7076edbc 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -302,7 +302,7 @@ nonzero_dec: '1' | '2' | '3' | '4' A _character literal_ is a single Unicode character enclosed within two `U+0027` (single-quote) characters, with the exception of `U+0027` itself, -which must be _escaped_ by a preceding U+005C character (`\`). +which must be _escaped_ by a preceding `U+005C` character (`\`). ##### String literals @@ -311,6 +311,19 @@ A _string literal_ is a sequence of any Unicode characters enclosed within two which must be _escaped_ by a preceding `U+005C` character (`\`), or a _raw string literal_. +A multi-line string literal may be defined by terminating each line with a +`U+005C` character (`\`) immediately before the newline. This causes the +`U+005C` character, the newline, and all whitespace at the beginning of the +next line to be ignored. + +```rust +let a = "foobar"; +let b = "foo\ + bar"; +``` + +`a` is equivalent to `b`. + ##### Character escapes Some additional _escapes_ are available in either character or non-raw string From f618e2e1ec1d6b9f0b5c110f0dbfa385f3b583d3 Mon Sep 17 00:00:00 2001 From: Alexander Bliskovsky Date: Wed, 25 Feb 2015 20:29:13 -0500 Subject: [PATCH 09/25] Changed prose to assert_eq! macro. --- src/doc/reference.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index 81e7076edbc..87130c08991 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -320,9 +320,9 @@ next line to be ignored. let a = "foobar"; let b = "foo\ bar"; -``` -`a` is equivalent to `b`. +assert_eq!(a,b); +``` ##### Character escapes From 8b2ff472cf0d1e348cc369e2e2927dc552582b32 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Wed, 25 Feb 2015 08:20:34 +0200 Subject: [PATCH 10/25] remove some compiler warnings --- src/libcollections/slice.rs | 4 ++-- src/libcollections/vec.rs | 4 ++-- src/libcoretest/slice.rs | 6 +++--- src/librustc/middle/astconv_util.rs | 3 +-- src/librustc_resolve/lib.rs | 2 +- src/libserialize/json.rs | 2 -- src/libstd/io/cursor.rs | 12 ++++++------ src/libsyntax/ast_util.rs | 8 ++++---- src/rustbook/book.rs | 8 ++++---- 9 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index d4c53739686..a2924f8fe53 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -2663,7 +2663,7 @@ mod tests { let (left, right) = values.split_at_mut(2); { let left: &[_] = left; - assert!(left[..left.len()] == [1, 2][]); + assert!(left[..left.len()] == [1, 2]); } for p in left { *p += 1; @@ -2671,7 +2671,7 @@ mod tests { { let right: &[_] = right; - assert!(right[..right.len()] == [3, 4, 5][]); + assert!(right[..right.len()] == [3, 4, 5]); } for p in right { *p += 2; diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 6d4541b5bde..c43c6c739d9 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -2090,7 +2090,7 @@ mod tests { let (left, right) = values.split_at_mut(2); { let left: &[_] = left; - assert!(&left[..left.len()] == &[1, 2][]); + assert!(&left[..left.len()] == &[1, 2]); } for p in left { *p += 1; @@ -2098,7 +2098,7 @@ mod tests { { let right: &[_] = right; - assert!(&right[..right.len()] == &[3, 4, 5][]); + assert!(&right[..right.len()] == &[3, 4, 5]); } for p in right { *p += 2; diff --git a/src/libcoretest/slice.rs b/src/libcoretest/slice.rs index 46c7730cc64..fe73b3b4407 100644 --- a/src/libcoretest/slice.rs +++ b/src/libcoretest/slice.rs @@ -59,16 +59,16 @@ fn iterator_to_slice() { let mut iter = data.iter_mut(); assert_eq!(&iter[..], &other_data[..]); // mutability: - assert!(&mut iter[] == other_data); + assert!(&mut iter[..] == other_data); iter.next(); assert_eq!(&iter[..], &other_data[1..]); - assert!(&mut iter[] == &mut other_data[1..]); + assert!(&mut iter[..] == &mut other_data[1..]); iter.next_back(); assert_eq!(&iter[..], &other_data[1..2]); - assert!(&mut iter[] == &mut other_data[1..2]); + assert!(&mut iter[..] == &mut other_data[1..2]); let s = iter.into_slice(); assert!(s == &mut other_data[1..2]); diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs index 17fd80ceaea..0f98b3c33fb 100644 --- a/src/librustc/middle/astconv_util.rs +++ b/src/librustc/middle/astconv_util.rs @@ -68,7 +68,7 @@ pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty) Some(d) => d.full_def() }; if let def::DefPrimTy(nty) = def { - Some(prim_ty_to_ty(tcx, &path.segments[], nty)) + Some(prim_ty_to_ty(tcx, &path.segments, nty)) } else { None } @@ -76,4 +76,3 @@ pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty) None } } - diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 95523be68c3..78ce9abe07d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2985,7 +2985,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } else { let msg = format!("use of undeclared trait name `{}`", self.path_names_to_string(trait_path, path_depth)); - self.resolve_error(trait_path.span, &msg[]); + self.resolve_error(trait_path.span, &msg); Err(()) } } diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 05d4e0f59fe..14930f91c91 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -3945,9 +3945,7 @@ mod tests { #[test] fn test_encode_hashmap_with_arbitrary_key() { - use std::old_io::Writer; use std::collections::HashMap; - use std::fmt; #[derive(PartialEq, Eq, Hash, RustcEncodable)] struct ArbitraryType(uint); let mut hm: HashMap = HashMap::new(); diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index f6cb4a8c9f3..b1779587528 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -173,7 +173,7 @@ mod tests { assert_eq!(writer.write(&[1, 2, 3]), Ok(3)); assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4)); let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; - assert_eq!(&writer.get_ref()[], b); + assert_eq!(&writer.get_ref()[..], b); } #[test] @@ -369,28 +369,28 @@ mod tests { assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4)); assert_eq!(writer.position(), 8); let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; - assert_eq!(&writer.get_ref()[], b); + assert_eq!(&writer.get_ref()[..], b); assert_eq!(writer.seek(SeekFrom::Start(0)), Ok(0)); assert_eq!(writer.position(), 0); assert_eq!(writer.write(&[3, 4]), Ok(2)); let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7]; - assert_eq!(&writer.get_ref()[], b); + assert_eq!(&writer.get_ref()[..], b); assert_eq!(writer.seek(SeekFrom::Current(1)), Ok(3)); assert_eq!(writer.write(&[0, 1]), Ok(2)); let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7]; - assert_eq!(&writer.get_ref()[], b); + assert_eq!(&writer.get_ref()[..], b); assert_eq!(writer.seek(SeekFrom::End(-1)), Ok(7)); assert_eq!(writer.write(&[1, 2]), Ok(2)); let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2]; - assert_eq!(&writer.get_ref()[], b); + assert_eq!(&writer.get_ref()[..], b); assert_eq!(writer.seek(SeekFrom::End(1)), Ok(10)); assert_eq!(writer.write(&[1]), Ok(1)); let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]; - assert_eq!(&writer.get_ref()[], b); + assert_eq!(&writer.get_ref()[..], b); } #[test] diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 79f0433761d..264e05f5c8d 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -760,13 +760,13 @@ mod test { #[test] fn idents_name_eq_test() { assert!(segments_name_eq( &[Ident{name:Name(3),ctxt:4}, Ident{name:Name(78),ctxt:82}] - .iter().map(ident_to_segment).collect::>()[], + .iter().map(ident_to_segment).collect::>(), &[Ident{name:Name(3),ctxt:104}, Ident{name:Name(78),ctxt:182}] - .iter().map(ident_to_segment).collect::>()[])); + .iter().map(ident_to_segment).collect::>())); assert!(!segments_name_eq( &[Ident{name:Name(3),ctxt:4}, Ident{name:Name(78),ctxt:82}] - .iter().map(ident_to_segment).collect::>()[], + .iter().map(ident_to_segment).collect::>(), &[Ident{name:Name(3),ctxt:104}, Ident{name:Name(77),ctxt:182}] - .iter().map(ident_to_segment).collect::>()[])); + .iter().map(ident_to_segment).collect::>())); } } diff --git a/src/rustbook/book.rs b/src/rustbook/book.rs index 3c116aa860b..8900b60d191 100644 --- a/src/rustbook/book.rs +++ b/src/rustbook/book.rs @@ -114,12 +114,12 @@ pub fn parse_summary(input: R, src: &Path) -> Result i, None => continue }; + let star_idx = match line.find("*") { Some(i) => i, None => continue }; - let start_bracket = star_idx + line[star_idx..].find_str("[").unwrap(); - let end_bracket = start_bracket + line[start_bracket..].find_str("](").unwrap(); + let start_bracket = star_idx + line[star_idx..].find("[").unwrap(); + let end_bracket = start_bracket + line[start_bracket..].find("](").unwrap(); let start_paren = end_bracket + 1; - let end_paren = start_paren + line[start_paren..].find_str(")").unwrap(); + let end_paren = start_paren + line[start_paren..].find(")").unwrap(); let given_path = &line[start_paren + 1 .. end_paren]; let title = line[start_bracket + 1..end_bracket].to_string(); From 19cb8f32d894719ece5b2308dabab45be1b94fcf Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 25 Feb 2015 22:34:21 +1100 Subject: [PATCH 11/25] Check stability of struct fields. We were recording stability attributes applied to fields in the compiler, and even annotating it in the libs, but the compiler didn't actually do the checks to give errors/warnings in user crates. --- src/librustc/lint/builtin.rs | 5 + src/librustc/middle/stability.rs | 121 ++++++ src/librustc/middle/ty.rs | 3 + src/libstd/old_io/mem.rs | 1 + src/test/auxiliary/lint_stability.rs | 24 +- src/test/auxiliary/lint_stability_fields.rs | 60 +++ .../compile-fail/lint-stability-fields.rs | 346 ++++++++++++++++++ src/test/compile-fail/lint-stability.rs | 12 +- 8 files changed, 561 insertions(+), 11 deletions(-) create mode 100644 src/test/auxiliary/lint_stability_fields.rs create mode 100644 src/test/compile-fail/lint-stability-fields.rs diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index a4f69e651df..0bd7f83b959 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1771,6 +1771,11 @@ impl LintPass for Stability { stability::check_path(cx.tcx, path, id, &mut |id, sp, stab| self.lint(cx, id, sp, stab)); } + + fn check_pat(&mut self, cx: &Context, pat: &ast::Pat) { + stability::check_pat(cx.tcx, pat, + &mut |id, sp, stab| self.lint(cx, id, sp, stab)) + } } declare_lint! { diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index f67e470ee54..ddac6cc7514 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -58,8 +58,10 @@ impl<'a> Annotator<'a> { attrs: &Vec, item_sp: Span, f: F, required: bool) where F: FnOnce(&mut Annotator), { + debug!("annotate(id = {:?}, attrs = {:?})", id, attrs); match attr::find_stability(self.sess.diagnostic(), attrs, item_sp) { Some(stab) => { + debug!("annotate: found {:?}", stab); self.index.local.insert(id, stab.clone()); // Don't inherit #[stable(feature = "rust1", since = "1.0.0")] @@ -72,6 +74,8 @@ impl<'a> Annotator<'a> { } } None => { + debug!("annotate: not found, use_parent = {:?}, parent = {:?}", + use_parent, self.parent); if use_parent { if let Some(stab) = self.parent.clone() { self.index.local.insert(id, stab); @@ -299,6 +303,12 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> { &mut |id, sp, stab| self.check(id, sp, stab)); visit::walk_path(self, path) } + + fn visit_pat(&mut self, pat: &ast::Pat) { + check_pat(self.tcx, pat, + &mut |id, sp, stab| self.check(id, sp, stab)); + visit::walk_pat(self, pat) + } } /// Helper for discovering nodes to check for stability @@ -385,6 +395,76 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr, None => return } } + ast::ExprField(ref base_e, ref field) => { + span = field.span; + match ty::expr_ty_adjusted(tcx, base_e).sty { + ty::ty_struct(did, _) => { + ty::lookup_struct_fields(tcx, did) + .iter() + .find(|f| f.name == field.node.name) + .unwrap_or_else(|| { + tcx.sess.span_bug(field.span, + "stability::check_expr: unknown named field access") + }) + .id + } + _ => tcx.sess.span_bug(e.span, + "stability::check_expr: named field access on non-struct") + } + } + ast::ExprTupField(ref base_e, ref field) => { + span = field.span; + match ty::expr_ty_adjusted(tcx, base_e).sty { + ty::ty_struct(did, _) => { + ty::lookup_struct_fields(tcx, did) + .get(field.node) + .unwrap_or_else(|| { + tcx.sess.span_bug(field.span, + "stability::check_expr: unknown unnamed field access") + }) + .id + } + ty::ty_tup(..) => return, + _ => tcx.sess.span_bug(e.span, + "stability::check_expr: unnamed field access on \ + something other than a tuple or struct") + } + } + ast::ExprStruct(_, ref expr_fields, _) => { + let type_ = ty::expr_ty(tcx, e); + match type_.sty { + ty::ty_struct(did, _) => { + let struct_fields = ty::lookup_struct_fields(tcx, did); + // check the stability of each field that appears + // in the construction expression. + for field in expr_fields { + let did = struct_fields + .iter() + .find(|f| f.name == field.ident.node.name) + .unwrap_or_else(|| { + tcx.sess.span_bug(field.span, + "stability::check_expr: unknown named \ + field access") + }) + .id; + maybe_do_stability_check(tcx, did, field.span, cb); + } + + // we're done. + return + } + // we don't look at stability attributes on + // struct-like enums (yet...), but it's definitely not + // a bug to have construct one. + ty::ty_enum(..) => return, + _ => { + tcx.sess.span_bug(e.span, + &format!("stability::check_expr: struct construction \ + of non-struct, type {:?}", + type_.repr(tcx))); + } + } + } _ => return }; @@ -403,6 +483,47 @@ pub fn check_path(tcx: &ty::ctxt, path: &ast::Path, id: ast::NodeId, } +pub fn check_pat(tcx: &ty::ctxt, pat: &ast::Pat, + cb: &mut FnMut(ast::DefId, Span, &Option)) { + debug!("check_pat(pat = {:?})", pat); + if is_internal(tcx, pat.span) { return; } + + let did = match ty::pat_ty_opt(tcx, pat) { + Some(&ty::TyS { sty: ty::ty_struct(did, _), .. }) => did, + Some(_) | None => return, + }; + let struct_fields = ty::lookup_struct_fields(tcx, did); + match pat.node { + // Foo(a, b, c) + ast::PatEnum(_, Some(ref pat_fields)) => { + for (field, struct_field) in pat_fields.iter().zip(struct_fields.iter()) { + // a .. pattern is fine, but anything positional is + // not. + if let ast::PatWild(ast::PatWildMulti) = field.node { + continue + } + maybe_do_stability_check(tcx, struct_field.id, field.span, cb) + } + } + // Foo { a, b, c } + ast::PatStruct(_, ref pat_fields, _) => { + for field in pat_fields { + let did = struct_fields + .iter() + .find(|f| f.name == field.node.ident.name) + .unwrap_or_else(|| { + tcx.sess.span_bug(field.span, + "stability::check_pat: unknown named field access") + }) + .id; + maybe_do_stability_check(tcx, did, field.span, cb); + } + } + // everything else is fine. + _ => {} + } +} + fn maybe_do_stability_check(tcx: &ty::ctxt, id: ast::DefId, span: Span, cb: &mut FnMut(ast::DefId, Span, &Option)) { if !is_staged_api(tcx, id) { return } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 78b8d4f7b1e..17ac7605741 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4298,6 +4298,9 @@ pub fn free_region_from_def(outlives_extent: region::DestructionScopeData, pub fn pat_ty<'tcx>(cx: &ctxt<'tcx>, pat: &ast::Pat) -> Ty<'tcx> { return node_id_to_type(cx, pat.id); } +pub fn pat_ty_opt<'tcx>(cx: &ctxt<'tcx>, pat: &ast::Pat) -> Option> { + return node_id_to_type_opt(cx, pat.id); +} // Returns the type of an expression as a monotype. diff --git a/src/libstd/old_io/mem.rs b/src/libstd/old_io/mem.rs index c08a2c1f477..e6a8b90ea33 100644 --- a/src/libstd/old_io/mem.rs +++ b/src/libstd/old_io/mem.rs @@ -102,6 +102,7 @@ impl MemWriter { impl Writer for MemWriter { #[inline] + #[allow(deprecated)] fn write_all(&mut self, buf: &[u8]) -> IoResult<()> { self.buf.push_all(buf); Ok(()) diff --git a/src/test/auxiliary/lint_stability.rs b/src/test/auxiliary/lint_stability.rs index fb535eb8336..d47575403e1 100644 --- a/src/test/auxiliary/lint_stability.rs +++ b/src/test/auxiliary/lint_stability.rs @@ -100,14 +100,22 @@ pub trait UnstableTrait { fn dummy(&self) { } } #[stable(feature = "test_feature", since = "1.0.0")] #[deprecated(since = "1.0.0")] -pub struct DeprecatedStruct { pub i: int } +pub struct DeprecatedStruct { + #[stable(feature = "test_feature", since = "1.0.0")] pub i: int +} #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] -pub struct DeprecatedUnstableStruct { pub i: int } +pub struct DeprecatedUnstableStruct { + #[stable(feature = "test_feature", since = "1.0.0")] pub i: int +} #[unstable(feature = "test_feature")] -pub struct UnstableStruct { pub i: int } +pub struct UnstableStruct { + #[stable(feature = "test_feature", since = "1.0.0")] pub i: int +} #[stable(feature = "rust1", since = "1.0.0")] -pub struct StableStruct { pub i: int } +pub struct StableStruct { + #[stable(feature = "test_feature", since = "1.0.0")] pub i: int +} #[stable(feature = "test_feature", since = "1.0.0")] #[deprecated(since = "1.0.0")] @@ -137,14 +145,14 @@ pub enum Enum { #[stable(feature = "test_feature", since = "1.0.0")] #[deprecated(since = "1.0.0")] -pub struct DeprecatedTupleStruct(pub int); +pub struct DeprecatedTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int); #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] -pub struct DeprecatedUnstableTupleStruct(pub int); +pub struct DeprecatedUnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int); #[unstable(feature = "test_feature")] -pub struct UnstableTupleStruct(pub int); +pub struct UnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int); #[stable(feature = "rust1", since = "1.0.0")] -pub struct StableTupleStruct(pub int); +pub struct StableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub int); #[macro_export] macro_rules! macro_test { diff --git a/src/test/auxiliary/lint_stability_fields.rs b/src/test/auxiliary/lint_stability_fields.rs new file mode 100644 index 00000000000..66940ee0081 --- /dev/null +++ b/src/test/auxiliary/lint_stability_fields.rs @@ -0,0 +1,60 @@ +// 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(staged_api)] +#![staged_api] +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Stable { + #[stable(feature = "rust1", since = "1.0.0")] + pub inherit: u8, // it's a lie (stable doesn't inherit) + #[unstable(feature = "test_feature")] + pub override1: u8, + #[deprecated(since = "1.0.0")] + #[unstable(feature = "test_feature")] + pub override2: u8, +} + +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Stable2(#[stable(feature = "rust1", since = "1.0.0")] pub u8, + #[unstable(feature = "test_feature")] pub u8, + #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] pub u8); + +#[unstable(feature = "test_feature")] +pub struct Unstable { + pub inherit: u8, + #[stable(feature = "rust1", since = "1.0.0")] + pub override1: u8, + #[deprecated(since = "1.0.0")] + #[unstable(feature = "test_feature")] + pub override2: u8, +} + +#[unstable(feature = "test_feature")] +pub struct Unstable2(pub u8, + #[stable(feature = "rust1", since = "1.0.0")] pub u8, + #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] pub u8); + +#[unstable(feature = "test_feature")] +#[deprecated(feature = "rust1", since = "1.0.0")] +pub struct Deprecated { + pub inherit: u8, + #[stable(feature = "rust1", since = "1.0.0")] + pub override1: u8, + #[unstable(feature = "test_feature")] + pub override2: u8, +} + +#[unstable(feature = "test_feature")] +#[deprecated(feature = "rust1", since = "1.0.0")] +pub struct Deprecated2(pub u8, + #[stable(feature = "rust1", since = "1.0.0")] pub u8, + #[unstable(feature = "test_feature")] pub u8); diff --git a/src/test/compile-fail/lint-stability-fields.rs b/src/test/compile-fail/lint-stability-fields.rs new file mode 100644 index 00000000000..c43ff198925 --- /dev/null +++ b/src/test/compile-fail/lint-stability-fields.rs @@ -0,0 +1,346 @@ +// 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:lint_stability_fields.rs +#![deny(deprecated)] +#![allow(dead_code)] +#![feature(staged_api)] +#![staged_api] + +mod cross_crate { + extern crate lint_stability_fields; + + use self::lint_stability_fields::*; + + pub fn foo() { + let x = Stable { + inherit: 1, + override1: 2, //~ WARN use of unstable + override2: 3, + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + }; + + let _ = x.inherit; + let _ = x.override1; //~ WARN use of unstable + let _ = x.override2; + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + + let Stable { + inherit: _, + override1: _, //~ WARN use of unstable + override2: _ + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + } = x; + // all fine + let Stable { .. } = x; + + let x = Stable2(1, 2, 3); + + let _ = x.0; + let _ = x.1; //~ WARN use of unstable + let _ = x.2; + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + + let Stable2(_, + _, //~ WARN use of unstable + _) + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + = x; + // all fine + let Stable2(..) = x; + + + let x = Unstable { //~ WARN use of unstable + inherit: 1, //~ WARN use of unstable + override1: 2, + override2: 3, + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + }; + + let _ = x.inherit; //~ WARN use of unstable + let _ = x.override1; + let _ = x.override2; + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + + let Unstable { //~ WARN use of unstable + inherit: _, //~ WARN use of unstable + override1: _, + override2: _ + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + } = x; + + let Unstable //~ WARN use of unstable + // the patterns are all fine: + { .. } = x; + + + let x = Unstable2(1, 2, 3); //~ WARN use of unstable + + let _ = x.0; //~ WARN use of unstable + let _ = x.1; + let _ = x.2; + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + + let Unstable2 //~ WARN use of unstable + (_, //~ WARN use of unstable + _, + _) + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + = x; + let Unstable2 //~ WARN use of unstable + // the patterns are all fine: + (..) = x; + + + let x = Deprecated { + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + inherit: 1, + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + override1: 2, + override2: 3, //~ WARN use of unstable + }; + + let _ = x.inherit; + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + let _ = x.override1; + let _ = x.override2; //~ WARN use of unstable + + let Deprecated { + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + inherit: _, + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + override1: _, + override2: _ //~ WARN use of unstable + } = x; + + let Deprecated + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + // the patterns are all fine: + { .. } = x; + + let x = Deprecated2(1, 2, 3); + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + + let _ = x.0; + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + let _ = x.1; + let _ = x.2; //~ WARN use of unstable + + let Deprecated2 + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + (_, + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + _, + _) //~ WARN use of unstable + = x; + let Deprecated2 + //~^ ERROR use of deprecated item + //~^^ WARN use of unstable + // the patterns are all fine: + (..) = x; + } +} + +mod this_crate { + #[stable(feature = "rust1", since = "1.0.0")] + struct Stable { + inherit: u8, + #[unstable(feature = "test_feature")] + override1: u8, + #[deprecated(since = "1.0.0")] + #[unstable(feature = "test_feature")] + override2: u8, + } + + #[stable(feature = "rust1", since = "1.0.0")] + struct Stable2(u8, + #[stable(feature = "rust1", since = "1.0.0")] u8, + #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] u8); + + #[unstable(feature = "test_feature")] + struct Unstable { + inherit: u8, + #[stable(feature = "rust1", since = "1.0.0")] + override1: u8, + #[deprecated(since = "1.0.0")] + #[unstable(feature = "test_feature")] + override2: u8, + } + + #[unstable(feature = "test_feature")] + struct Unstable2(u8, + #[stable(feature = "rust1", since = "1.0.0")] u8, + #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] u8); + + #[unstable(feature = "test_feature")] + #[deprecated(feature = "rust1", since = "1.0.0")] + struct Deprecated { + inherit: u8, + #[stable(feature = "rust1", since = "1.0.0")] + override1: u8, + #[unstable(feature = "test_feature")] + override2: u8, + } + + #[unstable(feature = "test_feature")] + #[deprecated(feature = "rust1", since = "1.0.0")] + struct Deprecated2(u8, + #[stable(feature = "rust1", since = "1.0.0")] u8, + #[unstable(feature = "test_feature")] u8); + + pub fn foo() { + let x = Stable { + inherit: 1, + override1: 2, + override2: 3, + //~^ ERROR use of deprecated item + }; + + let _ = x.inherit; + let _ = x.override1; + let _ = x.override2; + //~^ ERROR use of deprecated item + + let Stable { + inherit: _, + override1: _, + override2: _ + //~^ ERROR use of deprecated item + } = x; + // all fine + let Stable { .. } = x; + + let x = Stable2(1, 2, 3); + + let _ = x.0; + let _ = x.1; + let _ = x.2; + //~^ ERROR use of deprecated item + + let Stable2(_, + _, + _) + //~^ ERROR use of deprecated item + = x; + // all fine + let Stable2(..) = x; + + + let x = Unstable { + inherit: 1, + override1: 2, + override2: 3, + //~^ ERROR use of deprecated item + }; + + let _ = x.inherit; + let _ = x.override1; + let _ = x.override2; + //~^ ERROR use of deprecated item + + let Unstable { + inherit: _, + override1: _, + override2: _ + //~^ ERROR use of deprecated item + } = x; + + let Unstable + // the patterns are all fine: + { .. } = x; + + + let x = Unstable2(1, 2, 3); + + let _ = x.0; + let _ = x.1; + let _ = x.2; + //~^ ERROR use of deprecated item + + let Unstable2 + (_, + _, + _) + //~^ ERROR use of deprecated item + = x; + let Unstable2 + // the patterns are all fine: + (..) = x; + + + let x = Deprecated { + //~^ ERROR use of deprecated item + inherit: 1, + //~^ ERROR use of deprecated item + override1: 2, + override2: 3, + }; + + let _ = x.inherit; + //~^ ERROR use of deprecated item + let _ = x.override1; + let _ = x.override2; + + let Deprecated { + //~^ ERROR use of deprecated item + inherit: _, + //~^ ERROR use of deprecated item + override1: _, + override2: _ + } = x; + + let Deprecated + //~^ ERROR use of deprecated item + // the patterns are all fine: + { .. } = x; + + let x = Deprecated2(1, 2, 3); + //~^ ERROR use of deprecated item + + let _ = x.0; + //~^ ERROR use of deprecated item + let _ = x.1; + let _ = x.2; + + let Deprecated2 + //~^ ERROR use of deprecated item + (_, + //~^ ERROR use of deprecated item + _, + _) + = x; + let Deprecated2 + //~^ ERROR use of deprecated item + // the patterns are all fine: + (..) = x; + } +} + +fn main() {} diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs index 90792848855..12548c45396 100644 --- a/src/test/compile-fail/lint-stability.rs +++ b/src/test/compile-fail/lint-stability.rs @@ -317,11 +317,17 @@ mod this_crate { #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] - pub struct DeprecatedStruct { i: isize } + pub struct DeprecatedStruct { + #[stable(feature = "test_feature", since = "1.0.0")] i: isize + } #[unstable(feature = "test_feature")] - pub struct UnstableStruct { i: isize } + pub struct UnstableStruct { + #[stable(feature = "test_feature", since = "1.0.0")] i: isize + } #[stable(feature = "rust1", since = "1.0.0")] - pub struct StableStruct { i: isize } + pub struct StableStruct { + #[stable(feature = "test_feature", since = "1.0.0")] i: isize + } #[unstable(feature = "test_feature")] #[deprecated(since = "1.0.0")] From eafdc7135b79d2e51da740b67946512d949632a1 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 25 Feb 2015 22:37:12 +1100 Subject: [PATCH 12/25] Record the publicity of struct fields and enum variants. The stability check checks the `PublicItems` map when giving errors if there is a #[stable] item with a public contents that doesn't not have its own stability. Without recording this, struct fields and enum variants will not get errors for e.g. stable modules with unmarked functions internally. This is just improving the compiler's precision to give the standard library developers more information earlier. E.g. #![staged_api] #![feature(staged_api)] #![crate_type = "lib"] #[stable(feature = "rust1", since = "1.0.0")] pub struct Foo { pub x: i32 } #[stable(feature = "rust1", since = "1.0.0")] pub mod bar { pub fn baz() {} } Without the patch it gives: test.rs:12:5: 12:20 error: This node does not have a stability attribute test.rs:12 pub fn baz() {} ^~~~~~~~~~~~~~~ error: aborting due to previous error With the patch it gives: test.rs:7:9: 7:15 error: This node does not have a stability attribute test.rs:7 pub x: i32 ^~~~~~ test.rs:12:5: 12:20 error: This node does not have a stability attribute test.rs:12 pub fn baz() {} ^~~~~~~~~~~~~~~ error: aborting due to 2 previous errors --- src/librustc_privacy/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 436a826687e..46729988bb6 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -233,6 +233,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { ast::ItemEnum(ref def, _) if public_first => { for variant in &def.variants { self.exported_items.insert(variant.node.id); + self.public_items.insert(variant.node.id); } } @@ -321,6 +322,15 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { Some(id) => { self.exported_items.insert(id); } None => {} } + // fields can be public or private, so lets check + for field in &def.fields { + let vis = match field.node.kind { + ast::NamedField(_, vis) | ast::UnnamedField(vis) => vis + }; + if vis == ast::Public { + self.public_items.insert(field.node.id); + } + } } ast::ItemTy(ref ty, _) if public_first => { From 9cdb2568ca3c1fd5569b3073e757ccee0ec6c5a8 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Thu, 26 Feb 2015 17:36:49 +0800 Subject: [PATCH 13/25] remove the redundant else branch The branch "else { continue }" is the last code inside a loop body, it is just useless. Signed-off-by: Lai Jiangshan --- src/libcore/iter.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index b4ccf930437..c119bf799f5 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -1637,8 +1637,6 @@ impl Iterator for Filter where P: FnMut(&I::Item) -> bool for x in self.iter.by_ref() { if (self.predicate)(&x) { return Some(x); - } else { - continue } } None From 2d0e6caeeca9dbf60018b6308e20d3c907e24d78 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 25 Feb 2015 15:45:33 +0100 Subject: [PATCH 14/25] Add `push_ctxt` instrumentation to all functions that might call `base::zero_mem`. (Instrumentation work for Issue 22536.) --- src/librustc_trans/trans/_match.rs | 1 + src/librustc_trans/trans/cleanup.rs | 1 + src/librustc_trans/trans/datum.rs | 1 + src/librustc_trans/trans/intrinsic.rs | 2 ++ 4 files changed, 5 insertions(+) diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 9a121a8830b..48ff4c83320 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -1499,6 +1499,7 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, fn create_dummy_locals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, pat: &ast::Pat) -> Block<'blk, 'tcx> { + let _icx = push_ctxt("create_dummy_locals"); // create dummy memory for the variables if we have no // value to store into them immediately let tcx = bcx.tcx(); diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index a3705a67cdc..cb9156be479 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -1007,6 +1007,7 @@ impl<'tcx> Cleanup<'tcx> for DropValue<'tcx> { bcx: Block<'blk, 'tcx>, debug_loc: DebugLoc) -> Block<'blk, 'tcx> { + let _icx = base::push_ctxt("::trans"); let bcx = if self.is_immediate { glue::drop_ty_immediate(bcx, self.val, self.ty, debug_loc) } else { diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs index 8262dbf55dd..636c902d363 100644 --- a/src/librustc_trans/trans/datum.rs +++ b/src/librustc_trans/trans/datum.rs @@ -311,6 +311,7 @@ impl KindOps for Lvalue { val: ValueRef, ty: Ty<'tcx>) -> Block<'blk, 'tcx> { + let _icx = push_ctxt("::post_store"); if type_needs_drop(bcx.tcx(), ty) { // cancel cleanup of affine values by zeroing out let () = zero_mem(bcx, val, ty); diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 993c9eae45b..0706189a567 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -156,6 +156,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let ccx = fcx.ccx; let tcx = bcx.tcx(); + let _icx = push_ctxt("trans_intrinsic_call"); + let ret_ty = match callee_ty.sty { ty::ty_bare_fn(_, ref f) => { ty::erase_late_bound_regions(bcx.tcx(), &f.sig.output()) From 5e4867eef1bb0836dd88405e8a4e5af6d9798e6a Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 25 Feb 2015 23:09:58 +0100 Subject: [PATCH 15/25] Use more precise `type_needs_drop` for deciding about emitting cleanup code. Fix #22536 --- src/librustc_trans/trans/callee.rs | 2 +- src/librustc_trans/trans/cleanup.rs | 7 ++-- src/librustc_trans/trans/common.rs | 43 ++++++++++++++++++++++++- src/librustc_trans/trans/controlflow.rs | 2 +- src/librustc_trans/trans/datum.rs | 4 +-- src/librustc_trans/trans/expr.rs | 6 ++-- src/librustc_trans/trans/glue.rs | 14 ++++++-- src/librustc_trans/trans/intrinsic.rs | 3 +- src/librustc_trans/trans/meth.rs | 2 +- src/librustc_trans/trans/tvec.rs | 3 +- 10 files changed, 69 insertions(+), 17 deletions(-) diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 59fcd5492eb..4f234fac9a4 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -734,7 +734,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, }; if !is_rust_fn || type_of::return_uses_outptr(ccx, ret_ty) || - common::type_needs_drop(bcx.tcx(), ret_ty) { + bcx.fcx.type_needs_drop(ret_ty) { // Push the out-pointer if we use an out-pointer for this // return type, otherwise push "undef". if common::type_is_zero_size(ccx, ret_ty) { diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index cb9156be479..ad07f3953cc 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -386,7 +386,7 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { cleanup_scope: ScopeId, val: ValueRef, ty: Ty<'tcx>) { - if !common::type_needs_drop(self.ccx.tcx(), ty) { return; } + if !self.type_needs_drop(ty) { return; } let drop = box DropValue { is_immediate: false, must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty), @@ -408,7 +408,8 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { cleanup_scope: ScopeId, val: ValueRef, ty: Ty<'tcx>) { - if !common::type_needs_drop(self.ccx.tcx(), ty) { return; } + if !self.type_needs_drop(ty) { return; } + let drop = box DropValue { is_immediate: false, must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty), @@ -432,7 +433,7 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { val: ValueRef, ty: Ty<'tcx>) { - if !common::type_needs_drop(self.ccx.tcx(), ty) { return; } + if !self.type_needs_drop(ty) { return; } let drop = box DropValue { is_immediate: true, must_unwind: common::type_needs_unwind_cleanup(self.ccx, ty), diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index d8fc6df2685..ec7ed2fe890 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -213,8 +213,43 @@ pub fn type_needs_unwind_cleanup<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty< } } +/// If `type_needs_drop` returns true, then `ty` is definitely +/// non-copy and *might* have a destructor attached; if it returns +/// false, then `ty` definitely has no destructor (i.e. no drop glue). +/// +/// (Note that this implies that if `ty` has a destructor attached, +/// then `type_needs_drop` will definitely return `true` for `ty`.) pub fn type_needs_drop<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { - ty::type_contents(cx, ty).needs_drop(cx) + type_needs_drop_given_env(cx, ty, &ty::empty_parameter_environment(cx)) +} + +/// Core implementation of type_needs_drop, potentially making use of +/// and/or updating caches held in the `param_env`. +fn type_needs_drop_given_env<'a,'tcx>(cx: &ty::ctxt<'tcx>, + ty: Ty<'tcx>, + param_env: &ty::ParameterEnvironment<'a,'tcx>) -> bool { + // Issue #22536: We first query type_moves_by_default. It sees a + // normalized version of the type, and therefore will definitely + // know whether the type implements Copy (and thus needs no + // cleanup/drop/zeroing) ... + let implements_copy = !ty::type_moves_by_default(¶m_env, DUMMY_SP, ty); + + if implements_copy { return false; } + + // ... (issue #22536 continued) but as an optimization, still use + // prior logic of asking if the `needs_drop` bit is set; we need + // not zero non-Copy types if they have no destructor. + + // FIXME(#22815): Note that calling `ty::type_contents` is a + // conservative heuristic; it may report that `needs_drop` is set + // when actual type does not actually have a destructor associated + // with it. But since `ty` absolutely did not have the `Copy` + // bound attached (see above), it is sound to treat it as having a + // destructor (e.g. zero its memory on move). + + let contents = ty::type_contents(cx, ty); + debug!("type_needs_drop ty={} contents={:?}", ty.repr(cx), contents); + contents.needs_drop(cx) } fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { @@ -534,6 +569,12 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { self.param_substs, value) } + + /// This is the same as `common::type_needs_drop`, except that it + /// may use or update caches within this `FunctionContext`. + pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { + type_needs_drop_given_env(self.ccx.tcx(), ty, &self.param_env) + } } // Basic block context. We create a block context for each basic block diff --git a/src/librustc_trans/trans/controlflow.rs b/src/librustc_trans/trans/controlflow.rs index ad96c506c9d..85d0bc0319f 100644 --- a/src/librustc_trans/trans/controlflow.rs +++ b/src/librustc_trans/trans/controlflow.rs @@ -77,7 +77,7 @@ pub fn trans_stmt_semi<'blk, 'tcx>(cx: Block<'blk, 'tcx>, e: &ast::Expr) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_stmt_semi"); let ty = expr_ty(cx, e); - if type_needs_drop(cx.tcx(), ty) { + if cx.fcx.type_needs_drop(ty) { expr::trans_to_lvalue(cx, e, "stmt").bcx } else { expr::trans_into(cx, e, expr::Ignore) diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs index 636c902d363..6ca71254868 100644 --- a/src/librustc_trans/trans/datum.rs +++ b/src/librustc_trans/trans/datum.rs @@ -312,7 +312,7 @@ impl KindOps for Lvalue { ty: Ty<'tcx>) -> Block<'blk, 'tcx> { let _icx = push_ctxt("::post_store"); - if type_needs_drop(bcx.tcx(), ty) { + if bcx.fcx.type_needs_drop(ty) { // cancel cleanup of affine values by zeroing out let () = zero_mem(bcx, val, ty); bcx @@ -657,7 +657,7 @@ impl<'tcx, K: KindOps + fmt::Debug> Datum<'tcx, K> { /// scalar-ish (like an int or a pointer) which (1) does not require drop glue and (2) is /// naturally passed around by value, and not by reference. pub fn to_llscalarish<'blk>(self, bcx: Block<'blk, 'tcx>) -> ValueRef { - assert!(!type_needs_drop(bcx.tcx(), self.ty)); + assert!(!bcx.fcx.type_needs_drop(self.ty)); assert!(self.appropriate_rvalue_mode(bcx.ccx()) == ByValue); if self.kind.is_by_ref() { load_ty(bcx, self.val, self.ty) diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 5cc1baf66c6..27f9b9506a5 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -974,7 +974,7 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let src_datum = unpack_datum!(bcx, trans(bcx, &**src)); let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &**dst, "assign")); - if type_needs_drop(bcx.tcx(), dst_datum.ty) { + if bcx.fcx.type_needs_drop(dst_datum.ty) { // If there are destructors involved, make sure we // are copying from an rvalue, since that cannot possible // alias an lvalue. We are concerned about code like: @@ -1498,7 +1498,7 @@ pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, assert_eq!(discr, 0); match ty::expr_kind(bcx.tcx(), &*base.expr) { - ty::RvalueDpsExpr | ty::RvalueDatumExpr if !type_needs_drop(bcx.tcx(), ty) => { + ty::RvalueDpsExpr | ty::RvalueDatumExpr if !bcx.fcx.type_needs_drop(ty) => { bcx = trans_into(bcx, &*base.expr, SaveIn(addr)); }, ty::RvalueStmtExpr => bcx.tcx().sess.bug("unexpected expr kind for struct base expr"), @@ -2116,7 +2116,7 @@ fn trans_assign_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Evaluate LHS (destination), which should be an lvalue let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op")); - assert!(!type_needs_drop(bcx.tcx(), dst_datum.ty)); + assert!(!bcx.fcx.type_needs_drop(dst_datum.ty)); let dst_ty = dst_datum.ty; let dst = load_ty(bcx, dst_datum.val, dst_datum.ty); diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index c14683aeade..9491c8377a6 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -99,6 +99,16 @@ pub fn get_drop_glue_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, if !type_is_sized(tcx, t) { return t } + + // FIXME (#22815): note that type_needs_drop conservatively + // approximates in some cases and may say a type expression + // requires drop glue when it actually does not. + // + // (In this case it is not clear whether any harm is done, i.e. + // erroneously returning `t` in some cases where we could have + // returned `tcx.types.i8` does not appear unsound. The impact on + // code quality is unknown at this time.) + if !type_needs_drop(tcx, t) { return tcx.types.i8; } @@ -125,7 +135,7 @@ pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // NB: v is an *alias* of type t here, not a direct value. debug!("drop_ty(t={})", t.repr(bcx.tcx())); let _icx = push_ctxt("drop_ty"); - if type_needs_drop(bcx.tcx(), t) { + if bcx.fcx.type_needs_drop(t) { let ccx = bcx.ccx(); let glue = get_drop_glue(ccx, t); let glue_type = get_drop_glue_type(ccx, t); @@ -480,7 +490,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>) }, _ => { assert!(type_is_sized(bcx.tcx(), t)); - if type_needs_drop(bcx.tcx(), t) && ty::type_is_structural(t) { + if bcx.fcx.type_needs_drop(t) && ty::type_is_structural(t) { iter_structural_ty(bcx, v0, t, diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 0706189a567..54644c92869 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -378,7 +378,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } (_, "needs_drop") => { let tp_ty = *substs.types.get(FnSpace, 0); - C_bool(ccx, type_needs_drop(ccx.tcx(), tp_ty)) + + C_bool(ccx, bcx.fcx.type_needs_drop(tp_ty)) } (_, "owns_managed") => { let tp_ty = *substs.types.get(FnSpace, 0); diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 3411f12886d..4423cd27744 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -454,7 +454,7 @@ fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let self_datum = unpack_datum!( bcx, expr::trans(bcx, self_expr)); - let llval = if type_needs_drop(bcx.tcx(), self_datum.ty) { + let llval = if bcx.fcx.type_needs_drop(self_datum.ty) { let self_datum = unpack_datum!( bcx, self_datum.to_rvalue_datum(bcx, "trait_callee")); diff --git a/src/librustc_trans/trans/tvec.rs b/src/librustc_trans/trans/tvec.rs index d3acd23e641..a5c3923336a 100644 --- a/src/librustc_trans/trans/tvec.rs +++ b/src/librustc_trans/trans/tvec.rs @@ -53,11 +53,10 @@ pub fn make_drop_glue_unboxed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let not_null = IsNotNull(bcx, vptr); with_cond(bcx, not_null, |bcx| { let ccx = bcx.ccx(); - let tcx = bcx.tcx(); let _icx = push_ctxt("tvec::make_drop_glue_unboxed"); let dataptr = get_dataptr(bcx, vptr); - let bcx = if type_needs_drop(tcx, unit_ty) { + let bcx = if bcx.fcx.type_needs_drop(unit_ty) { let len = get_len(bcx, vptr); iter_vec_raw(bcx, dataptr, From 4e334d6141d239f97347bd2a93e2499414ecbc47 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 25 Feb 2015 23:45:41 +0100 Subject: [PATCH 16/25] Regression test for #22536. --- .../run-pass/issue-22536-copy-mustnt-zero.rs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/test/run-pass/issue-22536-copy-mustnt-zero.rs diff --git a/src/test/run-pass/issue-22536-copy-mustnt-zero.rs b/src/test/run-pass/issue-22536-copy-mustnt-zero.rs new file mode 100644 index 00000000000..b3492180a58 --- /dev/null +++ b/src/test/run-pass/issue-22536-copy-mustnt-zero.rs @@ -0,0 +1,34 @@ +// 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. + +// Regression test for Issue #22536: If a type implements Copy, then +// moving it must not zero the original memory. + +trait Resources { + type Buffer: Copy; + fn foo(&self) {} +} + +struct BufferHandle { + raw: ::Buffer, +} +impl Copy for BufferHandle {} + +enum Res {} +impl Resources for Res { + type Buffer = u32; +} +impl Copy for Res { } + +fn main() { + let b: BufferHandle = BufferHandle { raw: 1 }; + let c = b; + assert_eq!(c.raw, b.raw) +} From 9a6e3b900f458fd82c25e7679be2c8860aba4f22 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 26 Feb 2015 14:35:08 +0100 Subject: [PATCH 17/25] Add doc to `core::intrinsics` pointing out conservativeness of `needs_drop`. --- src/libcore/intrinsics.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index e7af0be88a0..1ca243134cc 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -241,7 +241,12 @@ extern "rust-intrinsic" { /// will trigger a compiler error. pub fn return_address() -> *const u8; - /// Returns `true` if a type requires drop glue. + /// Returns `true` if the actual type given as `T` requires drop + /// glue; returns `false` if the actual type provided for `T` + /// implements `Copy`. + /// + /// If the actual type neither requires drop glue nor implements + /// `Copy`, then may return `true` or `false`. pub fn needs_drop() -> bool; /// Returns `true` if a type is managed (will be allocated on the local heap) From 704ce1d735cc885718fc5d1d4b2b5ca55410271e Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 26 Feb 2015 15:22:13 +0200 Subject: [PATCH 18/25] Revert hacks and add test for LLVM aborts due to empty aggregates. Closes #21721. --- src/librand/reseeding.rs | 6 +----- src/test/bench/task-perf-alloc-unwind.rs | 10 ++++------ src/test/run-pass/issue-17216.rs | 4 +--- src/test/run-pass/issue-21721.rs | 17 +++++++++++++++++ 4 files changed, 23 insertions(+), 14 deletions(-) create mode 100644 src/test/run-pass/issue-21721.rs diff --git a/src/librand/reseeding.rs b/src/librand/reseeding.rs index f4d3e975b75..06828911471 100644 --- a/src/librand/reseeding.rs +++ b/src/librand/reseeding.rs @@ -134,11 +134,7 @@ pub trait Reseeder { /// Reseed an RNG using a `Default` instance. This reseeds by /// replacing the RNG with the result of a `Default::default` call. #[derive(Copy)] -pub struct ReseedWithDefault { __hack: [u8; 0] } -// FIXME(#21721) used to be an unit struct but that can cause -// certain LLVM versions to abort during optimizations. -#[allow(non_upper_case_globals)] -pub const ReseedWithDefault: ReseedWithDefault = ReseedWithDefault { __hack: [] }; +pub struct ReseedWithDefault; impl Reseeder for ReseedWithDefault { fn reseed(&mut self, rng: &mut R) { diff --git a/src/test/bench/task-perf-alloc-unwind.rs b/src/test/bench/task-perf-alloc-unwind.rs index 6b412c47cd7..896b0ee57a0 100644 --- a/src/test/bench/task-perf-alloc-unwind.rs +++ b/src/test/bench/task-perf-alloc-unwind.rs @@ -40,9 +40,7 @@ fn run(repeat: int, depth: int) { } } -// FIXME(#21721) used to be `List<()>` but that can cause -// certain LLVM versions to abort during optimizations. -type nillist = List<[u8; 0]>; +type nillist = List<()>; // Filled with things that have to be unwound @@ -83,11 +81,11 @@ fn recurse_or_panic(depth: int, st: Option) { } Some(st) => { let mut v = st.vec.clone(); - v.push_all(&[box List::Cons([], st.vec.last().unwrap().clone())]); + v.push_all(&[box List::Cons((), st.vec.last().unwrap().clone())]); State { - unique: box List::Cons([], box *st.unique), + unique: box List::Cons((), box *st.unique), vec: v, - res: r(box List::Cons([], st.res._l.clone())), + res: r(box List::Cons((), st.res._l.clone())), } } }; diff --git a/src/test/run-pass/issue-17216.rs b/src/test/run-pass/issue-17216.rs index ce5a0aa96e3..aa53a7658e1 100644 --- a/src/test/run-pass/issue-17216.rs +++ b/src/test/run-pass/issue-17216.rs @@ -25,9 +25,7 @@ fn main() { let mut dropped = false; { let leak = Leak { dropped: &mut dropped }; - // FIXME(#21721) "hack" used to be () but that can cause - // certain LLVM versions to abort during optimizations. - for (_, leaked) in Some(("hack", leak)).into_iter() {} + for ((), leaked) in Some(((), leak)).into_iter() {} } assert!(dropped); diff --git a/src/test/run-pass/issue-21721.rs b/src/test/run-pass/issue-21721.rs new file mode 100644 index 00000000000..fee14061c56 --- /dev/null +++ b/src/test/run-pass/issue-21721.rs @@ -0,0 +1,17 @@ +// 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() { + static NONE: Option<((), &'static u8)> = None; + let ptr = unsafe { + *(&NONE as *const _ as *const *const u8) + }; + assert!(ptr.is_null()); +} From d0bb57cfc38bfa2347c4b65ee6abd20a9462847c Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Thu, 26 Feb 2015 14:17:28 +0200 Subject: [PATCH 19/25] Fixed build with jemalloc disabled --- src/liballoc/heap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index d3d86270d1e..726d5c8a23b 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -300,7 +300,7 @@ mod imp { libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8 } else { let new_ptr = allocate(size, align); - ptr::copy_memory(new_ptr, ptr, cmp::min(size, old_size)); + ptr::copy(new_ptr, ptr, cmp::min(size, old_size)); deallocate(ptr, old_size, align); new_ptr } From 804c071d8b9cfe4d40df9565558db8a9d87d7775 Mon Sep 17 00:00:00 2001 From: Dave Huseby Date: Thu, 26 Feb 2015 13:03:06 -0800 Subject: [PATCH 20/25] fixing a few bitrig build breakers --- src/libstd/sys/unix/fs.rs | 15 --------------- src/libstd/sys/unix/process2.rs | 1 + 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 1c28d629d40..71b6214460f 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -291,29 +291,14 @@ fn mkstat(stat: &libc::stat) -> FileStat { // FileStat times are in milliseconds fn mktime(secs: u64, nsecs: u64) -> u64 { secs * 1000 + nsecs / 1000000 } - #[cfg(target_os = "bitrig")] - fn ctime(stat: &libc::stat) -> u64 { - mktime(stat.st_ctim.tv_sec as u64, stat.st_ctim.tv_nsec as u64) - } - #[cfg(not(target_os = "bitrig"))] fn ctime(stat: &libc::stat) -> u64 { mktime(stat.st_ctime as u64, stat.st_ctime_nsec as u64) } - #[cfg(target_os = "bitrig")] - fn atime(stat: &libc::stat) -> u64 { - mktime(stat.st_atim.tv_sec as u64, stat.st_atim.tv_nsec as u64) - } - #[cfg(not(target_os = "bitrig"))] fn atime(stat: &libc::stat) -> u64 { mktime(stat.st_atime as u64, stat.st_atime_nsec as u64) } - #[cfg(target_os = "bitrig")] - fn mtime(stat: &libc::stat) -> u64 { - mktime(stat.st_mtim.tv_sec as u64, stat.st_mtim.tv_nsec as u64) - } - #[cfg(not(target_os = "bitrig"))] fn mtime(stat: &libc::stat) -> u64 { mktime(stat.st_mtime as u64, stat.st_mtime_nsec as u64) } diff --git a/src/libstd/sys/unix/process2.rs b/src/libstd/sys/unix/process2.rs index b7a1b002f55..a7d0a864a08 100644 --- a/src/libstd/sys/unix/process2.rs +++ b/src/libstd/sys/unix/process2.rs @@ -439,6 +439,7 @@ fn translate_status(status: c_int) -> ExitStatus { target_os = "ios", target_os = "freebsd", target_os = "dragonfly", + target_os = "bitrig", target_os = "openbsd"))] mod imp { pub fn WIFEXITED(status: i32) -> bool { (status & 0x7f) == 0 } From 6b01f7ac0520473d8c043fb4fe706c2bd0b3dce5 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Thu, 26 Feb 2015 23:22:15 +0200 Subject: [PATCH 21/25] doc: the last mention of the word 'iterator' is redundant --- src/libcore/iter.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 8f767e62678..7921c9a1d5a 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -171,8 +171,7 @@ pub trait IteratorExt: Iterator + Sized { self.fold(0, |cnt, _x| cnt + 1) } - /// Loops through the entire iterator, returning the last element of the - /// iterator. + /// Loops through the entire iterator, returning the last element. /// /// # Examples /// From c9168cca72105297a5d66dee0beb0bb192cb01ad Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Thu, 26 Feb 2015 15:31:24 +0100 Subject: [PATCH 22/25] libtest: flush output after every write Useful for debugging tests that hang forever. --- src/libtest/lib.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 82c1a4b1195..7c7f1fd478a 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -506,16 +506,25 @@ impl ConsoleTestState { if self.use_color { try!(term.reset()); } - Ok(()) + term.flush() + } + Raw(ref mut stdout) => { + try!(stdout.write_all(word.as_bytes())); + stdout.flush() } - Raw(ref mut stdout) => stdout.write_all(word.as_bytes()) } } pub fn write_plain(&mut self, s: &str) -> old_io::IoResult<()> { match self.out { - Pretty(ref mut term) => term.write_all(s.as_bytes()), - Raw(ref mut stdout) => stdout.write_all(s.as_bytes()) + Pretty(ref mut term) => { + try!(term.write_all(s.as_bytes())); + term.flush() + }, + Raw(ref mut stdout) => { + try!(stdout.write_all(s.as_bytes())); + stdout.flush() + }, } } From 060661d2b4a323c83a1bf043234eae8a344ff6aa Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 25 Feb 2015 23:12:22 +1100 Subject: [PATCH 23/25] Add some missing stability attributes on struct fields. --- src/libcore/str/mod.rs | 1 + src/libstd/sync/mpsc/mod.rs | 2 +- src/libstd/thread_local/mod.rs | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 7e51f8e8503..b354116993c 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -939,6 +939,7 @@ impl<'a, P: Pattern<'a>> Iterator for SplitStr<'a, P> { type Item = &'a str; #[inline] + #[allow(deprecated)] fn next(&mut self) -> Option<&'a str> { Iterator::next(&mut self.0) } diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 7bd1f3542eb..1310d476f8e 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -384,7 +384,7 @@ impl !Sync for SyncSender {} /// contains the data being sent as a payload so it can be recovered. #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, Clone, Copy)] -pub struct SendError(pub T); +pub struct SendError(#[stable(feature = "rust1", since = "1.0.0")] pub T); /// An error returned from the `recv` function on a `Receiver`. /// diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs index d65156dae96..764c7d730cb 100644 --- a/src/libstd/thread_local/mod.rs +++ b/src/libstd/thread_local/mod.rs @@ -105,10 +105,12 @@ pub struct Key { // This is trivially devirtualizable by LLVM because we never store anything // to this field and rustc can declare the `static` as constant as well. #[doc(hidden)] + #[unstable(feature = "thread_local_internals")] pub inner: fn() -> &'static __impl::KeyInner>>, // initialization routine to invoke to create a value #[doc(hidden)] + #[unstable(feature = "thread_local_internals")] pub init: fn() -> T, } From 9549350b874be76636388ef718a93caea96ada9f Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 26 Feb 2015 19:15:57 +0100 Subject: [PATCH 24/25] Refactor signaling of E0223 to avoid multiple span_errs for same code. --- src/librustc_typeck/astconv.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 844635117b5..d9dc050aebf 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -991,6 +991,17 @@ fn trait_ref_to_object_type<'tcx>(this: &AstConv<'tcx>, result } +fn report_ambiguous_associated_type(tcx: &ty::ctxt, + span: Span, + type_str: &str, + trait_str: &str, + name: &str) { + span_err!(tcx.sess, span, E0223, + "ambiguous associated type; specify the type using the syntax \ + `<{} as {}>::{}`", + type_str, trait_str, name); +} + fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, span: Span, ty: Ty<'tcx>, @@ -1011,10 +1022,8 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, let ty_param_node_id = if is_param { ty_path_def.local_node_id() } else { - span_err!(tcx.sess, span, E0223, - "ambiguous associated type; specify the type using the syntax \ - `<{} as Trait>::{}`", - ty.user_string(tcx), token::get_name(assoc_name)); + report_ambiguous_associated_type( + tcx, span, &ty.user_string(tcx), "Trait", &token::get_name(assoc_name)); return (tcx.types.err, ty_path_def); }; @@ -1109,10 +1118,8 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>, ty } else { let path_str = ty::item_path_str(tcx, trait_def_id); - span_err!(tcx.sess, span, E0223, - "ambiguous associated type; specify the type using the syntax \ - `::{}`", - path_str, &token::get_ident(item_segment.identifier)); + report_ambiguous_associated_type( + tcx, span, "Type", &path_str, &token::get_ident(item_segment.identifier)); return tcx.types.err; }; From bde4c1d6fbefcd914a06b5eab6ef6f9a6f26f271 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 27 Feb 2015 15:13:35 -0800 Subject: [PATCH 25/25] Test fixes and rebase conflicts --- src/test/auxiliary/static-methods-crate.rs | 6 ++---- src/test/run-pass/deriving-primitive.rs | 6 +++--- src/test/run-pass/match-with-ret-arm.rs | 4 +--- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/test/auxiliary/static-methods-crate.rs b/src/test/auxiliary/static-methods-crate.rs index d84ded25702..e61fb49add5 100644 --- a/src/test/auxiliary/static-methods-crate.rs +++ b/src/test/auxiliary/static-methods-crate.rs @@ -11,14 +11,12 @@ #![crate_name="static_methods_crate"] #![crate_type = "lib"] -use std::int; - pub trait read { fn readMaybe(s: String) -> Option; } -impl read for int { - fn readMaybe(s: String) -> Option { +impl read for isize { + fn readMaybe(s: String) -> Option { s.parse().ok() } } diff --git a/src/test/run-pass/deriving-primitive.rs b/src/test/run-pass/deriving-primitive.rs index eb3cb30594e..6b365c348f7 100644 --- a/src/test/run-pass/deriving-primitive.rs +++ b/src/test/run-pass/deriving-primitive.rs @@ -9,18 +9,18 @@ // except according to those terms. use std::num::FromPrimitive; -use std::int; +use std::isize; #[derive(PartialEq, FromPrimitive, Debug)] enum A { - Foo = int::MAX, + Foo = isize::MAX, Bar = 1, Baz = 3, Qux, } pub fn main() { - let x: Option = FromPrimitive::from_int(int::MAX); + let x: Option = FromPrimitive::from_int(isize::MAX); assert_eq!(x, Some(A::Foo)); let x: Option = FromPrimitive::from_int(1); diff --git a/src/test/run-pass/match-with-ret-arm.rs b/src/test/run-pass/match-with-ret-arm.rs index 05c6aac90e3..d2e27fc822e 100644 --- a/src/test/run-pass/match-with-ret-arm.rs +++ b/src/test/run-pass/match-with-ret-arm.rs @@ -8,13 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::uint; - pub fn main() { // sometimes we have had trouble finding // the right type for f, as we unified // bot and u32 here - let f = match "1234".parse::().ok() { + let f = match "1234".parse::().ok() { None => return (), Some(num) => num as u32 };