Skip to content

Commit 2932a21

Browse files
committed
---
yaml --- r: 89967 b: refs/heads/master c: 8d87e9d h: refs/heads/master i: 89965: b195c08 89963: 1c6dc4e 89959: 345c788 89951: 77915df v: v3
1 parent 3b9724f commit 2932a21

File tree

8 files changed

+149
-81
lines changed

8 files changed

+149
-81
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
refs/heads/master: 80dff186416180423fe8117cbd19930a6c813ed9
2+
refs/heads/master: 8d87e9da2146b911ded797eac1a7aa9464902617
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
44
refs/heads/snap-stage3: a6d3e57dca68fde4effdda3e4ae2887aa535fcd6
55
refs/heads/try: b160761e35efcd1207112b3b782c06633cf441a8

trunk/doc/tutorial.md

Lines changed: 47 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -890,9 +890,7 @@ calling the destructor, and the owner determines whether the object is mutable.
890890

891891
Ownership is recursive, so mutability is inherited recursively and a destructor
892892
destroys the contained tree of owned objects. Variables are top-level owners
893-
and destroy the contained object when they go out of scope. A box managed by
894-
the garbage collector starts a new ownership tree, and the destructor is called
895-
when it is collected.
893+
and destroy the contained object when they go out of scope.
896894

897895
~~~~
898896
// the struct owns the objects contained in the `x` and `y` fields
@@ -1009,51 +1007,6 @@ let mut s = r; // box becomes mutable
10091007
let t = s; // box becomes immutable
10101008
~~~~
10111009

1012-
# Managed boxes
1013-
1014-
A managed box (`@`) is a heap allocation with the lifetime managed by a
1015-
task-local garbage collector. It will be destroyed at some point after there
1016-
are no references left to the box, no later than the end of the task. Managed
1017-
boxes lack an owner, so they start a new ownership tree and don't inherit
1018-
mutability. They do own the contained object, and mutability is defined by the
1019-
type of the managed box (`@` or `@mut`). An object containing a managed box is
1020-
not `Owned`, and can't be sent between tasks.
1021-
1022-
~~~~
1023-
let a = @5; // immutable
1024-
1025-
let mut b = @5; // mutable variable, immutable box
1026-
b = @10;
1027-
1028-
let c = @mut 5; // immutable variable, mutable box
1029-
*c = 10;
1030-
1031-
let mut d = @mut 5; // mutable variable, mutable box
1032-
*d += 5;
1033-
d = @mut 15;
1034-
~~~~
1035-
1036-
A mutable variable and an immutable variable can refer to the same box, given
1037-
that their types are compatible. Mutability of a box is a property of its type,
1038-
however, so for example a mutable handle to an immutable box cannot be
1039-
assigned a reference to a mutable box.
1040-
1041-
~~~~
1042-
let a = @1; // immutable box
1043-
let b = @mut 2; // mutable box
1044-
1045-
let mut c : @int; // declare a variable with type managed immutable int
1046-
let mut d : @mut int; // and one of type managed mutable int
1047-
1048-
c = a; // box type is the same, okay
1049-
d = b; // box type is the same, okay
1050-
~~~~
1051-
1052-
~~~~ {.xfail-test}
1053-
// but b cannot be assigned to c, or a to d
1054-
c = b; // error
1055-
~~~~
1056-
10571010
# Borrowed pointers
10581011

10591012
Rust's borrowed pointers are a general purpose reference type. In contrast with
@@ -1347,6 +1300,52 @@ defined in [`std::vec`] and [`std::str`].
13471300
[`std::vec`]: std/vec/index.html
13481301
[`std::str`]: std/str/index.html
13491302
1303+
# Ownership escape hatches
1304+
1305+
Ownership can cleanly describe tree-like data structures, and borrowed pointers provide non-owning
1306+
references. However, more flexibility is often desired and Rust provides ways to escape from strict
1307+
single parent ownership.
1308+
1309+
The standard library provides the `std::rc::Rc` pointer type to express *shared ownership* over a
1310+
reference counted box. As soon as all of the `Rc` pointers go out of scope, the box and the
1311+
contained value are destroyed.
1312+
1313+
~~~
1314+
use std::rc::Rc;
1315+
1316+
// A fixed-size array allocated in a reference-counted box
1317+
let x = Rc::new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
1318+
let y = x.clone(); // a new owner
1319+
let z = x; // this moves `x` into `z`, rather than creating a new owner
1320+
1321+
assert_eq!(*z.borrow(), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
1322+
1323+
let mut a = Rc::new([10, 9, 8, 7, 6, 5, 4, 3, 2, 1]); // the variable is mutable, but not the box
1324+
a = z;
1325+
~~~
1326+
1327+
A garbage collected pointer is provided via `std::gc::Gc`, with a task-local garbage collector
1328+
having ownership of the box. It allows the creation of cycles, and the individual `Gc` pointers do
1329+
not have a destructor.
1330+
1331+
~~~
1332+
use std::gc::Gc;
1333+
1334+
// A fixed-size array allocated in a garbage-collected box
1335+
let x = Gc::new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
1336+
let y = x; // does not perform a move, unlike with `Rc`
1337+
let z = x;
1338+
1339+
assert_eq!(*z.borrow(), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
1340+
~~~
1341+
1342+
With shared ownership, mutability cannot be inherited so the boxes are always immutable. However,
1343+
it's possible to use *dynamic* mutability via types like `std::cell::Cell` where freezing is handled
1344+
via dynamic checks and can fail at runtime.
1345+
1346+
The `Rc` and `Gc` types are not sendable, so they cannot be used to share memory between tasks. Safe
1347+
immutable and mutable shared memory is provided by the `extra::arc` module.
1348+
13501349
# Closures
13511350
13521351
Named functions, like those we've seen so far, may not refer to local

trunk/src/librustc/middle/lint.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ pub enum lint {
7575
type_limits,
7676
type_overflow,
7777
unused_unsafe,
78+
unsafe_block,
7879

7980
managed_heap_memory,
8081
owned_heap_memory,
@@ -236,6 +237,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
236237
default: warn
237238
}),
238239

240+
("unsafe_block",
241+
LintSpec {
242+
lint: unsafe_block,
243+
desc: "usage of an `unsafe` block",
244+
default: allow
245+
}),
246+
239247
("unused_variable",
240248
LintSpec {
241249
lint: unused_variable,
@@ -870,8 +878,7 @@ fn check_pat_non_uppercase_statics(cx: &Context, p: &ast::Pat) {
870878

871879
fn check_unused_unsafe(cx: &Context, e: &ast::Expr) {
872880
match e.node {
873-
// Don't warn about generated blocks, that'll just pollute the
874-
// output.
881+
// Don't warn about generated blocks, that'll just pollute the output.
875882
ast::ExprBlock(ref blk) => {
876883
if blk.rules == ast::UnsafeBlock(ast::UserProvided) &&
877884
!cx.tcx.used_unsafe.contains(&blk.id) {
@@ -883,6 +890,16 @@ fn check_unused_unsafe(cx: &Context, e: &ast::Expr) {
883890
}
884891
}
885892

893+
fn check_unsafe_block(cx: &Context, e: &ast::Expr) {
894+
match e.node {
895+
// Don't warn about generated blocks, that'll just pollute the output.
896+
ast::ExprBlock(ref blk) if blk.rules == ast::UnsafeBlock(ast::UserProvided) => {
897+
cx.span_lint(unsafe_block, blk.span, "usage of an `unsafe` block");
898+
}
899+
_ => ()
900+
}
901+
}
902+
886903
fn check_unused_mut_pat(cx: &Context, p: @ast::Pat) {
887904
match p.node {
888905
ast::PatIdent(ast::BindByValue(ast::MutMutable),
@@ -1126,6 +1143,7 @@ impl<'self> Visitor<()> for Context<'self> {
11261143
check_while_true_expr(self, e);
11271144
check_stability(self, e);
11281145
check_unused_unsafe(self, e);
1146+
check_unsafe_block(self, e);
11291147
check_unnecessary_allocation(self, e);
11301148
check_heap_expr(self, e);
11311149

trunk/src/libstd/rand/distributions/mod.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -444,17 +444,17 @@ mod tests {
444444
fn test_rand_sample() {
445445
let mut rand_sample = RandSample::<ConstRand>;
446446

447-
assert_eq!(*rand_sample.sample(task_rng()), 0);
448-
assert_eq!(*rand_sample.ind_sample(task_rng()), 0);
447+
assert_eq!(*rand_sample.sample(&mut task_rng()), 0);
448+
assert_eq!(*rand_sample.ind_sample(&mut task_rng()), 0);
449449
}
450450

451451
#[test]
452452
fn test_normal() {
453453
let mut norm = Normal::new(10.0, 10.0);
454-
let rng = task_rng();
454+
let mut rng = task_rng();
455455
for _ in range(0, 1000) {
456-
norm.sample(rng);
457-
norm.ind_sample(rng);
456+
norm.sample(&mut rng);
457+
norm.ind_sample(&mut rng);
458458
}
459459
}
460460
#[test]
@@ -466,10 +466,10 @@ mod tests {
466466
#[test]
467467
fn test_exp() {
468468
let mut exp = Exp::new(10.0);
469-
let rng = task_rng();
469+
let mut rng = task_rng();
470470
for _ in range(0, 1000) {
471-
assert!(exp.sample(rng) >= 0.0);
472-
assert!(exp.ind_sample(rng) >= 0.0);
471+
assert!(exp.sample(&mut rng) >= 0.0);
472+
assert!(exp.ind_sample(&mut rng) >= 0.0);
473473
}
474474
}
475475
#[test]

trunk/src/libstd/rand/distributions/range.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ mod tests {
183183

184184
#[test]
185185
fn test_integers() {
186-
let rng = task_rng();
186+
let mut rng = task_rng();
187187
macro_rules! t (
188188
($($ty:ty),*) => {{
189189
$(
@@ -193,9 +193,9 @@ mod tests {
193193
for &(low, high) in v.iter() {
194194
let mut sampler: Range<$ty> = Range::new(low, high);
195195
for _ in range(0, 1000) {
196-
let v = sampler.sample(rng);
196+
let v = sampler.sample(&mut rng);
197197
assert!(low <= v && v < high);
198-
let v = sampler.ind_sample(rng);
198+
let v = sampler.ind_sample(&mut rng);
199199
assert!(low <= v && v < high);
200200
}
201201
}
@@ -208,7 +208,7 @@ mod tests {
208208

209209
#[test]
210210
fn test_floats() {
211-
let rng = task_rng();
211+
let mut rng = task_rng();
212212
macro_rules! t (
213213
($($ty:ty),*) => {{
214214
$(
@@ -219,9 +219,9 @@ mod tests {
219219
for &(low, high) in v.iter() {
220220
let mut sampler: Range<$ty> = Range::new(low, high);
221221
for _ in range(0, 1000) {
222-
let v = sampler.sample(rng);
222+
let v = sampler.sample(&mut rng);
223223
assert!(low <= v && v < high);
224-
let v = sampler.ind_sample(rng);
224+
let v = sampler.ind_sample(&mut rng);
225225
assert!(low <= v && v < high);
226226
}
227227
}

trunk/src/libstd/rand/mod.rs

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -577,11 +577,24 @@ impl reseeding::Reseeder<StdRng> for TaskRngReseeder {
577577
}
578578
}
579579
static TASK_RNG_RESEED_THRESHOLD: uint = 32_768;
580+
type TaskRngInner = reseeding::ReseedingRng<StdRng, TaskRngReseeder>;
580581
/// The task-local RNG.
581-
pub type TaskRng = reseeding::ReseedingRng<StdRng, TaskRngReseeder>;
582+
#[no_send]
583+
pub struct TaskRng {
584+
// This points into TLS (specifically, it points to the endpoint
585+
// of a ~ stored in TLS, to make it robust against TLS moving
586+
// things internally) and so this struct cannot be legally
587+
// transferred between tasks *and* it's unsafe to deallocate the
588+
// RNG other than when a task is finished.
589+
//
590+
// The use of unsafe code here is OK if the invariants above are
591+
// satisfied; and it allows us to avoid (unnecessarily) using a
592+
// GC'd or RC'd pointer.
593+
priv rng: *mut TaskRngInner
594+
}
582595

583596
// used to make space in TLS for a random number generator
584-
local_data_key!(TASK_RNG_KEY: @mut TaskRng)
597+
local_data_key!(TASK_RNG_KEY: ~TaskRngInner)
585598

586599
/// Retrieve the lazily-initialized task-local random number
587600
/// generator, seeded by the system. Intended to be used in method
@@ -594,34 +607,34 @@ local_data_key!(TASK_RNG_KEY: @mut TaskRng)
594607
/// if the operating system random number generator is rigged to give
595608
/// the same sequence always. If absolute consistency is required,
596609
/// explicitly select an RNG, e.g. `IsaacRng` or `Isaac64Rng`.
597-
pub fn task_rng() -> @mut TaskRng {
598-
let r = local_data::get(TASK_RNG_KEY, |k| k.map(|k| *k));
599-
match r {
610+
pub fn task_rng() -> TaskRng {
611+
local_data::get_mut(TASK_RNG_KEY, |rng| match rng {
600612
None => {
601-
let rng = @mut reseeding::ReseedingRng::new(StdRng::new(),
613+
let mut rng = ~reseeding::ReseedingRng::new(StdRng::new(),
602614
TASK_RNG_RESEED_THRESHOLD,
603615
TaskRngReseeder);
616+
let ptr = &mut *rng as *mut TaskRngInner;
617+
604618
local_data::set(TASK_RNG_KEY, rng);
605-
rng
619+
620+
TaskRng { rng: ptr }
606621
}
607-
Some(rng) => rng
608-
}
622+
Some(rng) => TaskRng { rng: &mut **rng }
623+
})
609624
}
610625

611-
// Allow direct chaining with `task_rng`
612-
impl<R: Rng> Rng for @mut R {
613-
#[inline]
626+
impl Rng for TaskRng {
614627
fn next_u32(&mut self) -> u32 {
615-
(**self).next_u32()
628+
unsafe { (*self.rng).next_u32() }
616629
}
617-
#[inline]
630+
618631
fn next_u64(&mut self) -> u64 {
619-
(**self).next_u64()
632+
unsafe { (*self.rng).next_u64() }
620633
}
621634

622635
#[inline]
623636
fn fill_bytes(&mut self, bytes: &mut [u8]) {
624-
(**self).fill_bytes(bytes);
637+
unsafe { (*self.rng).fill_bytes(bytes) }
625638
}
626639
}
627640

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#[allow(unused_unsafe)];
12+
#[deny(unsafe_block)];
13+
14+
unsafe fn allowed() {}
15+
16+
#[allow(unsafe_block)] fn also_allowed() { unsafe {} }
17+
18+
fn main() {
19+
unsafe {} //~ ERROR: usage of an `unsafe` block
20+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// ensure that the TaskRng isn't/doesn't become accidentally sendable.
12+
13+
fn test_send<S: Send>() {}
14+
15+
pub fn main() {
16+
test_send::<::std::rand::TaskRng>();
17+
//~^ ERROR: incompatible type `std::rand::TaskRng`, which does not fulfill `Send`
18+
}

0 commit comments

Comments
 (0)