From 103d02ff2fc5016ed3791a554301a7bb738ed96c Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Mon, 13 Apr 2015 14:49:10 -0700 Subject: [PATCH 1/7] lint: deny transmuting from immutable to mutable, since it's undefined behavior [breaking-change] Technically breaking, since code that had been using these transmutes before will no longer compile. However, it was undefined behavior, so really, it's a good thing. Fixing your code would require some re-working to use an UnsafeCell instead. Closes #13146 --- src/librustc_lint/builtin.rs | 66 +++++++++++++++++++ src/librustc_lint/lib.rs | 1 + .../compile-fail/transmute-imut-to-mut.rs | 20 ++++++ 3 files changed, 87 insertions(+) create mode 100644 src/test/compile-fail/transmute-imut-to-mut.rs diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 176ed9d97ff9a..141eb3fd1ae0f 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -2087,6 +2087,72 @@ impl LintPass for InvalidNoMangleItems { } } +#[derive(Clone, Copy)] +pub struct MutableTransmutes; + +declare_lint! { + MUTABLE_TRANSMUTES, + Deny, + "mutating transmuted &mut T from &T may cause undefined behavior" +} + +impl LintPass for MutableTransmutes { + fn get_lints(&self) -> LintArray { + lint_array!(MUTABLE_TRANSMUTES) + } + + fn check_expr(&mut self, cx: &Context, expr: &ast::Expr) { + use syntax::ast::DefId; + use syntax::abi::RustIntrinsic; + let msg = "mutating transmuted &mut T from &T may cause undefined behavior,\ + consider instead using an UnsafeCell"; + match get_transmute_from_to(cx, expr) { + Some((&ty::ty_rptr(_, from_mt), &ty::ty_rptr(_, to_mt))) => { + if to_mt.mutbl == ast::Mutability::MutMutable + && from_mt.mutbl == ast::Mutability::MutImmutable { + cx.span_lint(MUTABLE_TRANSMUTES, expr.span, msg); + } + } + _ => () + } + + fn get_transmute_from_to<'a, 'tcx>(cx: &Context<'a, 'tcx>, expr: &ast::Expr) + -> Option<(&'tcx ty::sty<'tcx>, &'tcx ty::sty<'tcx>)> { + match expr.node { + ast::ExprPath(..) => (), + _ => return None + } + if let DefFn(did, _) = ty::resolve_expr(cx.tcx, expr) { + if !def_id_is_transmute(cx, did) { + return None; + } + let typ = ty::node_id_to_type(cx.tcx, expr.id); + match typ.sty { + ty::ty_bare_fn(_, ref bare_fn) if bare_fn.abi == RustIntrinsic => { + if let ty::FnConverging(to) = bare_fn.sig.0.output { + let from = bare_fn.sig.0.inputs[0]; + return Some((&from.sty, &to.sty)); + } + }, + _ => () + } + } + None + } + + fn def_id_is_transmute(cx: &Context, def_id: DefId) -> bool { + match ty::lookup_item_type(cx.tcx, def_id).ty.sty { + ty::ty_bare_fn(_, ref bfty) if bfty.abi == RustIntrinsic => (), + _ => return false + } + ty::with_path(cx.tcx, def_id, |path| match path.last() { + Some(ref last) => last.name().as_str() == "transmute", + _ => false + }) + } + } +} + /// Forbids using the `#[feature(...)]` attribute #[derive(Copy, Clone)] pub struct UnstableFeatures; diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 0b13382f15483..195faaaab9e2e 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -110,6 +110,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { InvalidNoMangleItems, PluginAsLibrary, DropWithReprExtern, + MutableTransmutes, ); add_builtin_with_new!(sess, diff --git a/src/test/compile-fail/transmute-imut-to-mut.rs b/src/test/compile-fail/transmute-imut-to-mut.rs new file mode 100644 index 0000000000000..2e076337f53ef --- /dev/null +++ b/src/test/compile-fail/transmute-imut-to-mut.rs @@ -0,0 +1,20 @@ +// 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. + +// Tests that transmuting from &T to &mut T is Undefined Behavior. + +use std::mem::transmute; + +fn main() { + let _a: &mut u8 = unsafe { transmute(&1u8) }; + //~^ ERROR mutating transmuted &mut T from &T may cause undefined behavior +} + + From 8ed09972780d8d157cbe7f576d175284fbe097fa Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Mon, 13 Apr 2015 14:49:39 -0700 Subject: [PATCH 2/7] std: update select internals to not use mutable transmuting --- src/libstd/sync/mpsc/select.rs | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs index b8ad92841f2de..28aa829c68378 100644 --- a/src/libstd/sync/mpsc/select.rs +++ b/src/libstd/sync/mpsc/select.rs @@ -58,7 +58,7 @@ use core::prelude::*; -use core::cell::Cell; +use core::cell::{Cell, UnsafeCell}; use core::marker; use core::mem; use core::ptr; @@ -70,9 +70,13 @@ use sync::mpsc::blocking::{self, SignalToken}; /// The "receiver set" of the select interface. This structure is used to manage /// a set of receivers which are being selected over. pub struct Select { + inner: UnsafeCell, + next_id: Cell, +} + +struct SelectInner { head: *mut Handle<'static, ()>, tail: *mut Handle<'static, ()>, - next_id: Cell, } impl !marker::Send for Select {} @@ -84,7 +88,7 @@ pub struct Handle<'rx, T:Send+'rx> { /// The ID of this handle, used to compare against the return value of /// `Select::wait()` id: usize, - selector: &'rx Select, + selector: *mut SelectInner, next: *mut Handle<'static, ()>, prev: *mut Handle<'static, ()>, added: bool, @@ -127,8 +131,10 @@ impl Select { /// ``` pub fn new() -> Select { Select { - head: ptr::null_mut(), - tail: ptr::null_mut(), + inner: UnsafeCell::new(SelectInner { + head: ptr::null_mut(), + tail: ptr::null_mut(), + }), next_id: Cell::new(1), } } @@ -141,7 +147,7 @@ impl Select { self.next_id.set(id + 1); Handle { id: id, - selector: self, + selector: self.inner.get(), next: ptr::null_mut(), prev: ptr::null_mut(), added: false, @@ -250,7 +256,7 @@ impl Select { } } - fn iter(&self) -> Packets { Packets { cur: self.head } } + fn iter(&self) -> Packets { Packets { cur: unsafe { &*self.inner.get() }.head } } } impl<'rx, T: Send> Handle<'rx, T> { @@ -271,7 +277,7 @@ impl<'rx, T: Send> Handle<'rx, T> { /// while it is added to the `Select` set. pub unsafe fn add(&mut self) { if self.added { return } - let selector: &mut Select = mem::transmute(&*self.selector); + let selector = &mut *self.selector; let me: *mut Handle<'static, ()> = mem::transmute(&*self); if selector.head.is_null() { @@ -292,7 +298,7 @@ impl<'rx, T: Send> Handle<'rx, T> { pub unsafe fn remove(&mut self) { if !self.added { return } - let selector: &mut Select = mem::transmute(&*self.selector); + let selector = &mut *self.selector; let me: *mut Handle<'static, ()> = mem::transmute(&*self); if self.prev.is_null() { @@ -318,8 +324,10 @@ impl<'rx, T: Send> Handle<'rx, T> { #[unsafe_destructor] impl Drop for Select { fn drop(&mut self) { - assert!(self.head.is_null()); - assert!(self.tail.is_null()); + unsafe { + assert!((&*self.inner.get()).head.is_null()); + assert!((&*self.inner.get()).tail.is_null()); + } } } From 1fcfba1b42d76ad3789d2bf87144dc1386988642 Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Tue, 5 May 2015 11:40:41 -0700 Subject: [PATCH 3/7] test: update run-pass tests to not use mutable transmuting --- src/test/auxiliary/issue_8401.rs | 4 ++-- src/test/run-pass/issue-2718.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/auxiliary/issue_8401.rs b/src/test/auxiliary/issue_8401.rs index 04b56442d0b8f..40e01c1474a60 100644 --- a/src/test/auxiliary/issue_8401.rs +++ b/src/test/auxiliary/issue_8401.rs @@ -21,6 +21,6 @@ impl A for B {} fn bar(_: &mut A, _: &T) {} fn foo(t: &T) { - let b = B; - bar(unsafe { mem::transmute(&b as &A) }, t) + let mut b = B; + bar(&mut b as &mut A, t) } diff --git a/src/test/run-pass/issue-2718.rs b/src/test/run-pass/issue-2718.rs index 71d1439dd2bc8..329000c483f25 100644 --- a/src/test/run-pass/issue-2718.rs +++ b/src/test/run-pass/issue-2718.rs @@ -172,7 +172,7 @@ pub mod pipes { unsafe { if self.p != None { let self_p: &mut Option<*const packet> = - mem::transmute(&self.p); + mem::transmute(&mut self.p); let p = replace(self_p, None); sender_terminate(p.unwrap()) } @@ -202,7 +202,7 @@ pub mod pipes { unsafe { if self.p != None { let self_p: &mut Option<*const packet> = - mem::transmute(&self.p); + mem::transmute(&mut self.p); let p = replace(self_p, None); receiver_terminate(p.unwrap()) } From a0f0b1034aa31ec22f9819b66d73b3c2c778b6c9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 30 Apr 2015 15:24:39 -0700 Subject: [PATCH 4/7] std: Remove index notation on slice iterators These implementations were intended to be unstable, but currently the stability attributes cannot handle a stable trait with an unstable `impl` block. This commit also audits the rest of the standard library for explicitly-`#[unstable]` impl blocks. No others were removed but some annotations were changed to `#[stable]` as they're defacto stable anyway. One particularly interesting `impl` marked `#[stable]` as part of this commit is the `Add<&[T]>` impl for `Vec`, which uses `push_all` and implicitly clones all elements of the vector provided. Closes #24791 Conflicts: src/libcoretest/slice.rs src/librustc_driver/lib.rs --- src/libcollections/string.rs | 21 +++--- src/libcollections/vec.rs | 9 ++- src/libcore/iter.rs | 13 ++-- src/libcore/slice.rs | 110 ----------------------------- src/libcoretest/slice.rs | 46 ------------ src/librustc_driver/lib.rs | 8 +-- src/libstd/collections/hash/map.rs | 3 +- src/libstd/io/buffered.rs | 6 +- src/libstd/net/parser.rs | 2 +- 9 files changed, 29 insertions(+), 189 deletions(-) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 0f0254a32b1a4..ec4df92fa890b 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -742,8 +742,7 @@ impl<'a> FromIterator<&'a str> for String { } } -#[unstable(feature = "collections", - reason = "waiting on Extend stabilization")] +#[stable(feature = "rust1", since = "1.0.0")] impl Extend for String { fn extend>(&mut self, iterable: I) { let iterator = iterable.into_iter(); @@ -755,8 +754,7 @@ impl Extend for String { } } -#[unstable(feature = "collections", - reason = "waiting on Extend stabilization")] +#[stable(feature = "rust1", since = "1.0.0")] impl<'a> Extend<&'a str> for String { fn extend>(&mut self, iterable: I) { let iterator = iterable.into_iter(); @@ -871,8 +869,7 @@ impl hash::Hash for String { } } -#[unstable(feature = "collections", - reason = "recent addition, needs more experience")] +#[stable(feature = "rust1", since = "1.0.0")] impl<'a> Add<&'a str> for String { type Output = String; @@ -965,11 +962,17 @@ pub fn as_string<'a>(x: &'a str) -> DerefString<'a> { DerefString { x: as_vec(x.as_bytes()) } } -#[unstable(feature = "collections", reason = "associated error type may change")] +/// Error returned from `String::from_str` +#[unstable(feature = "str_parse_error", reason = "may want to be replaced with \ + Void if it ever exists")] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct ParseError(()); + +#[stable(feature = "rust1", since = "1.0.0")] impl FromStr for String { - type Err = (); + type Err = ParseError; #[inline] - fn from_str(s: &str) -> Result { + fn from_str(s: &str) -> Result { Ok(String::from_str(s)) } } diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 526150915a705..64beac78c8b5b 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1276,7 +1276,7 @@ pub fn from_elem(elem: T, n: usize) -> Vec { // Common trait implementations for Vec //////////////////////////////////////////////////////////////////////////////// -#[unstable(feature = "collections")] +#[stable(feature = "rust1", since = "1.0.0")] impl Clone for Vec { #[cfg(not(test))] fn clone(&self) -> Vec { <[T]>::to_vec(&**self) } @@ -1531,7 +1531,7 @@ impl<'a, T> IntoIterator for &'a mut Vec { } } -#[unstable(feature = "collections", reason = "waiting on Extend stability")] +#[stable(feature = "rust1", since = "1.0.0")] impl Extend for Vec { #[inline] fn extend>(&mut self, iterable: I) { @@ -1591,8 +1591,7 @@ impl Ord for Vec { } } -#[unstable(feature = "collections", - reason = "recent addition, needs more experience")] +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, T: Clone> Add<&'a [T]> for Vec { type Output = Vec; @@ -1672,7 +1671,7 @@ impl<'a> From<&'a str> for Vec { // Clone-on-write //////////////////////////////////////////////////////////////////////////////// -#[unstable(feature = "collections")] +#[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> FromIterator for Cow<'a, [T]> where T: Clone { fn from_iter>(it: I) -> Cow<'a, [T]> { Cow::Owned(FromIterator::from_iter(it)) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 233ed01811930..134b84d0c7aac 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -626,12 +626,10 @@ pub trait Iterator { /// # Examples /// /// ``` - /// # #![feature(core)] /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter(); /// assert!(it.any(|x| *x == 3)); - /// assert_eq!(&it[..], [4, 5]); - /// + /// assert_eq!(it.collect::>(), [&4, &5]); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -654,11 +652,10 @@ pub trait Iterator { /// # Examples /// /// ``` - /// # #![feature(core)] /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter(); /// assert_eq!(it.find(|&x| *x == 3).unwrap(), &3); - /// assert_eq!(&it[..], [4, 5]); + /// assert_eq!(it.collect::>(), [&4, &5]); #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn find

(&mut self, mut predicate: P) -> Option where @@ -678,11 +675,10 @@ pub trait Iterator { /// # Examples /// /// ``` - /// # #![feature(core)] /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter(); /// assert_eq!(it.position(|x| *x == 3).unwrap(), 2); - /// assert_eq!(&it[..], [4, 5]); + /// assert_eq!(it.collect::>(), [&4, &5]); #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn position

(&mut self, mut predicate: P) -> Option where @@ -708,11 +704,10 @@ pub trait Iterator { /// # Examples /// /// ``` - /// # #![feature(core)] /// let a = [1, 2, 2, 4, 5]; /// let mut it = a.iter(); /// assert_eq!(it.rposition(|x| *x == 2).unwrap(), 2); - /// assert_eq!(&it[..], [1, 2]); + /// assert_eq!(it.collect::>(), [&1, &2]); #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn rposition

(&mut self, mut predicate: P) -> Option where diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 1e96d761d405a..1c12d9f1a1029 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -736,46 +736,6 @@ pub struct Iter<'a, T: 'a> { unsafe impl<'a, T: Sync> Sync for Iter<'a, T> {} unsafe impl<'a, T: Sync> Send for Iter<'a, T> {} -#[unstable(feature = "core")] -impl<'a, T> ops::Index> for Iter<'a, T> { - type Output = [T]; - - #[inline] - fn index(&self, index: ops::Range) -> &[T] { - self.as_slice().index(index) - } -} - -#[unstable(feature = "core")] -impl<'a, T> ops::Index> for Iter<'a, T> { - type Output = [T]; - - #[inline] - fn index(&self, index: ops::RangeTo) -> &[T] { - self.as_slice().index(index) - } -} - -#[unstable(feature = "core")] -impl<'a, T> ops::Index> for Iter<'a, T> { - type Output = [T]; - - #[inline] - fn index(&self, index: ops::RangeFrom) -> &[T] { - self.as_slice().index(index) - } -} - -#[unstable(feature = "core")] -impl<'a, T> ops::Index for Iter<'a, T> { - type Output = [T]; - - #[inline] - fn index(&self, _index: RangeFull) -> &[T] { - self.as_slice() - } -} - impl<'a, T> Iter<'a, T> { /// View the underlying data as a subslice of the original data. /// @@ -833,76 +793,6 @@ pub struct IterMut<'a, T: 'a> { unsafe impl<'a, T: Sync> Sync for IterMut<'a, T> {} unsafe impl<'a, T: Send> Send for IterMut<'a, T> {} -#[unstable(feature = "core")] -impl<'a, T> ops::Index> for IterMut<'a, T> { - type Output = [T]; - - #[inline] - fn index(&self, index: ops::Range) -> &[T] { - self.index(RangeFull).index(index) - } -} -#[unstable(feature = "core")] -impl<'a, T> ops::Index> for IterMut<'a, T> { - type Output = [T]; - - #[inline] - fn index(&self, index: ops::RangeTo) -> &[T] { - self.index(RangeFull).index(index) - } -} -#[unstable(feature = "core")] -impl<'a, T> ops::Index> for IterMut<'a, T> { - type Output = [T]; - - #[inline] - fn index(&self, index: ops::RangeFrom) -> &[T] { - self.index(RangeFull).index(index) - } -} -#[unstable(feature = "core")] -impl<'a, T> ops::Index for IterMut<'a, T> { - type Output = [T]; - - #[inline] - fn index(&self, _index: RangeFull) -> &[T] { - make_slice!(T => &[T]: self.ptr, self.end) - } -} - -#[unstable(feature = "core")] -impl<'a, T> ops::IndexMut> for IterMut<'a, T> { - #[inline] - fn index_mut(&mut self, index: ops::Range) -> &mut [T] { - self.index_mut(RangeFull).index_mut(index) - } -} -#[unstable(feature = "core")] -impl<'a, T> ops::IndexMut> for IterMut<'a, T> { - - #[inline] - fn index_mut(&mut self, index: ops::RangeTo) -> &mut [T] { - self.index_mut(RangeFull).index_mut(index) - } -} -#[unstable(feature = "core")] -impl<'a, T> ops::IndexMut> for IterMut<'a, T> { - - #[inline] - fn index_mut(&mut self, index: ops::RangeFrom) -> &mut [T] { - self.index_mut(RangeFull).index_mut(index) - } -} -#[unstable(feature = "core")] -impl<'a, T> ops::IndexMut for IterMut<'a, T> { - - #[inline] - fn index_mut(&mut self, _index: RangeFull) -> &mut [T] { - make_mut_slice!(T => &mut [T]: self.ptr, self.end) - } -} - - impl<'a, T> IterMut<'a, T> { /// View the underlying data as a subslice of the original data. /// diff --git a/src/libcoretest/slice.rs b/src/libcoretest/slice.rs index fe73b3b440795..96114cbec55bc 100644 --- a/src/libcoretest/slice.rs +++ b/src/libcoretest/slice.rs @@ -35,50 +35,4 @@ fn binary_search_not_found() { } #[test] -fn iterator_to_slice() { - macro_rules! test { - ($data: expr) => {{ - let data: &mut [_] = &mut $data; - let other_data: &mut [_] = &mut $data; - - { - let mut iter = data.iter(); - assert_eq!(&iter[..], &other_data[..]); - - iter.next(); - assert_eq!(&iter[..], &other_data[1..]); - - iter.next_back(); - assert_eq!(&iter[..], &other_data[1..2]); - - let s = iter.as_slice(); - iter.next(); - assert_eq!(s, &other_data[1..2]); - } - { - let mut iter = data.iter_mut(); - assert_eq!(&iter[..], &other_data[..]); - // mutability: - assert!(&mut iter[..] == other_data); - - iter.next(); - assert_eq!(&iter[..], &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]); - - let s = iter.into_slice(); - assert!(s == &mut other_data[1..2]); - } - }} - } - - // try types of a variety of sizes - test!([(1u64, 1u64, 1u8), (2, 2, 2), (3, 3, 3)]); - test!([1u64,2,3]); - test!([1u8,2,3]); - test!([(),(),()]); } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 8f21a800d5c4d..deb5f89cc0c83 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -855,10 +855,10 @@ pub fn monitor(f: F) { pub fn diagnostics_registry() -> diagnostics::registry::Registry { use syntax::diagnostics::registry::Registry; - let all_errors = Vec::new() + - &rustc::diagnostics::DIAGNOSTICS[..] + - &rustc_typeck::diagnostics::DIAGNOSTICS[..] + - &rustc_resolve::diagnostics::DIAGNOSTICS[..]; + let mut all_errors = Vec::new(); + all_errors.push_all(&rustc::diagnostics::DIAGNOSTICS); + all_errors.push_all(&rustc_typeck::diagnostics::DIAGNOSTICS); + all_errors.push_all(&rustc_resolve::diagnostics::DIAGNOSTICS); Registry::new(&*all_errors) } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 16b2c45bd8dc6..3ad48622ca094 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1607,8 +1607,7 @@ impl HashState for RandomState { } } -#[unstable(feature = "std_misc", - reason = "hashing an hash maps may be altered")] +#[stable(feature = "rust1", since = "1.0.0")] impl Default for RandomState { #[inline] fn default() -> RandomState { diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index bd44a9547b496..e91c2dc77e972 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -120,7 +120,7 @@ impl fmt::Debug for BufReader where R: fmt::Debug { } } -#[unstable(feature = "buf_seek", reason = "recently added")] +#[stable(feature = "rust1", since = "1.0.0")] impl Seek for BufReader { /// Seek to an offset, in bytes, in the underlying reader. /// @@ -284,8 +284,8 @@ impl fmt::Debug for BufWriter where W: fmt::Debug { } } -#[unstable(feature = "buf_seek", reason = "recently added")] -impl Seek for BufWriter { +#[stable(feature = "rust1", since = "1.0.0")] +impl Seek for BufWriter { /// Seek to the offset, in bytes, in the underlying writer. /// /// Seeking always writes out the internal buffer before seeking. diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs index 7c1667a603f65..88cfc5a7b2d8d 100644 --- a/src/libstd/net/parser.rs +++ b/src/libstd/net/parser.rs @@ -291,7 +291,7 @@ impl<'a> Parser<'a> { } } -#[unstable(feature = "ip_addr", reason = "recent addition")] +#[stable(feature = "rust1", since = "1.0.0")] impl FromStr for IpAddr { type Err = AddrParseError; fn from_str(s: &str) -> Result { From e57059d4a0452b4a6290e8b6be30f91cd9d116ea Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 30 Apr 2015 15:45:48 -0700 Subject: [PATCH 5/7] std: Destabilize io::BufStream As pointed out in #17136 the semantics of a `BufStream` aren't always what one expects, and it looks like other [languages like C#][c-sharp] implement a buffered stream with only one underlying buffer. For now this commit destabilizes the primitive in the `std::io` module to give us some more time in figuring out what to do with it. [c-sharp]: https://msdn.microsoft.com/en-us/library/system.io.bufferedstream%28v=vs.110%29.aspx [breaking-change] --- src/libstd/io/buffered.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index e91c2dc77e972..73561b7c262f3 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -435,15 +435,19 @@ impl Read for InternalBufWriter { /// infrequent calls to `read` and `write` on the underlying `Read+Write`. /// /// The output buffer will be written out when this stream is dropped. -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "buf_stream", + reason = "unsure about semantics of buffering two directions, \ + leading to issues like #17136")] pub struct BufStream { inner: BufReader> } +#[unstable(feature = "buf_stream", + reason = "unsure about semantics of buffering two directions, \ + leading to issues like #17136")] impl BufStream { /// Creates a new buffered stream with explicitly listed capacities for the /// reader/writer buffer. - #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacities(reader_cap: usize, writer_cap: usize, inner: S) -> BufStream { let writer = BufWriter::with_capacity(writer_cap, inner); @@ -454,13 +458,11 @@ impl BufStream { /// Creates a new buffered stream with the default reader/writer buffer /// capacities. - #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: S) -> BufStream { BufStream::with_capacities(DEFAULT_BUF_SIZE, DEFAULT_BUF_SIZE, inner) } /// Gets a reference to the underlying stream. - #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &S { let InternalBufWriter(ref w) = self.inner.inner; w.get_ref() @@ -472,7 +474,6 @@ impl BufStream { /// /// It is inadvisable to read directly from or write directly to the /// underlying stream. - #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut S { let InternalBufWriter(ref mut w) = self.inner.inner; w.get_mut() @@ -482,7 +483,6 @@ impl BufStream { /// /// The internal write buffer is written out before returning the stream. /// Any leftover data in the read buffer is lost. - #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> Result>> { let BufReader { inner: InternalBufWriter(w), buf, pos, cap } = self.inner; w.into_inner().map_err(|IntoInnerError(w, e)| { @@ -493,20 +493,26 @@ impl BufStream { } } -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "buf_stream", + reason = "unsure about semantics of buffering two directions, \ + leading to issues like #17136")] impl BufRead for BufStream { fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() } fn consume(&mut self, amt: usize) { self.inner.consume(amt) } } -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "buf_stream", + reason = "unsure about semantics of buffering two directions, \ + leading to issues like #17136")] impl Read for BufStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } } -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "buf_stream", + reason = "unsure about semantics of buffering two directions, \ + leading to issues like #17136")] impl Write for BufStream { fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.inner.get_mut().write(buf) @@ -516,7 +522,9 @@ impl Write for BufStream { } } -#[stable(feature = "rust1", since = "1.0.0")] +#[unstable(feature = "buf_stream", + reason = "unsure about semantics of buffering two directions, \ + leading to issues like #17136")] impl fmt::Debug for BufStream where S: fmt::Debug { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let reader = &self.inner; From b94f1589f479a751ec98afd8ee108c7454d44d90 Mon Sep 17 00:00:00 2001 From: John Gallagher Date: Wed, 6 May 2015 11:47:11 -0400 Subject: [PATCH 6/7] Make RwLock::try_write try to obtain a write lock Conflicts: src/libstd/sync/rwlock.rs --- src/libstd/sync/rwlock.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 1ea92d5eff7fe..0f268520163cd 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -230,7 +230,7 @@ impl RwLock { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn try_write(&self) -> TryLockResult> { - if unsafe { self.inner.lock.try_read() } { + if unsafe { self.inner.lock.try_write() } { Ok(try!(RwLockWriteGuard::new(&*self.inner, &self.data))) } else { Err(TryLockError::WouldBlock) @@ -413,7 +413,7 @@ mod tests { use rand::{self, Rng}; use sync::mpsc::channel; use thread; - use sync::{Arc, RwLock, StaticRwLock, RW_LOCK_INIT}; + use sync::{Arc, RwLock, StaticRwLock, TryLockError, RW_LOCK_INIT}; #[test] fn smoke() { @@ -565,4 +565,21 @@ mod tests { let lock = arc.read().unwrap(); assert_eq!(*lock, 2); } + + #[test] + fn test_rwlock_try_write() { + use mem::drop; + + let lock = RwLock::new(0isize); + let read_guard = lock.read().unwrap(); + + let write_result = lock.try_write(); + match write_result { + Err(TryLockError::WouldBlock) => (), + Ok(_) => assert!(false, "try_write should not succeed while read_guard is in scope"), + Err(_) => assert!(false, "unexpected error"), + } + + drop(read_guard); + } } From 5136e9053622107b3d2cd9760ad4af37df847f3a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 6 May 2015 10:51:10 -0700 Subject: [PATCH 7/7] std: Remove addition on vectors for now Ideally this trait implementation would be unstable, requiring crates to opt-in if they would like the functionality, but that's not currently how stability works so the implementation needs to be removed entirely. This may come back at a future date, but for now the conservative option is to remove it. [breaking-change] Conflicts: src/libcollections/vec.rs --- src/libcollections/vec.rs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 64beac78c8b5b..a8105d976e599 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -59,7 +59,7 @@ use core::intrinsics::assume; use core::iter::{repeat, FromIterator}; use core::marker::PhantomData; use core::mem; -use core::ops::{Index, IndexMut, Deref, Add}; +use core::ops::{Index, IndexMut, Deref}; use core::ops; use core::ptr; use core::ptr::Unique; @@ -1591,17 +1591,6 @@ impl Ord for Vec { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: Clone> Add<&'a [T]> for Vec { - type Output = Vec; - - #[inline] - fn add(mut self, rhs: &[T]) -> Vec { - self.push_all(rhs); - self - } -} - #[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Vec {