Skip to content

Commit b37b092

Browse files
committed
---
yaml --- r: 273691 b: refs/heads/beta c: 5954fce h: refs/heads/master i: 273689: 7b8044c 273687: 42d969c
1 parent c7ada2a commit b37b092

File tree

10 files changed

+164
-83
lines changed

10 files changed

+164
-83
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ refs/tags/0.9: 36870b185fc5f5486636d4515f0e22677493f225
2323
refs/tags/0.10: ac33f2b15782272ae348dbd7b14b8257b2148b5a
2424
refs/tags/0.11.0: e1247cb1d0d681be034adb4b558b5a0c0d5720f9
2525
refs/tags/0.12.0: f0c419429ef30723ceaf6b42f9b5a2aeb5d2e2d1
26-
refs/heads/beta: e1080dca01affec0e9633ca79e7bafff52578ac9
26+
refs/heads/beta: 5954fce848a0105cdf2009278cd1b50daffb7c61
2727
refs/tags/1.0.0-alpha: e42bd6d93a1d3433c486200587f8f9e12590a4d7
2828
refs/heads/tmp: e06d2ad9fcd5027bcaac5b08fc9aa39a49d0ecd3
2929
refs/tags/1.0.0-alpha.2: 4c705f6bc559886632d3871b04f58aab093bfa2f

branches/beta/mk/crates.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
123123
test rustc_lint rustc_front
124124

125125

126-
TOOL_DEPS_compiletest := test getopts log
126+
TOOL_DEPS_compiletest := test getopts
127127
TOOL_DEPS_rustdoc := rustdoc
128128
TOOL_DEPS_rustc := rustc_driver
129129
TOOL_DEPS_rustbook := std rustdoc

branches/beta/mk/main.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ endif
493493
LD_LIBRARY_PATH_ENV_HOSTDIR$(1)_T_$(2)_H_$(3) := \
494494
$$(CURDIR)/$$(HLIB$(1)_H_$(3)):$$(CFG_LLVM_INST_DIR_$(3))/lib
495495
LD_LIBRARY_PATH_ENV_TARGETDIR$(1)_T_$(2)_H_$(3) := \
496-
$$(CURDIR)/$$(TLIB$(1)_T_$(2)_H_$(CFG_BUILD))
496+
$$(CURDIR)/$$(TLIB1_T_$(2)_H_$(CFG_BUILD))
497497

498498
HOST_RPATH_VAR$(1)_T_$(2)_H_$(3) := \
499499
$$(LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3))=$$(LD_LIBRARY_PATH_ENV_HOSTDIR$(1)_T_$(2)_H_$(3)):$$$$$$(LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3))

branches/beta/src/doc/book/concurrency.md

Lines changed: 124 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,54 @@ fn main() {
9494
}
9595
```
9696

97+
As closures can capture variables from their environment, we can also try to
98+
bring some data into the other thread:
99+
100+
```rust,ignore
101+
use std::thread;
102+
103+
fn main() {
104+
let x = 1;
105+
thread::spawn(|| {
106+
println!("x is {}", x);
107+
});
108+
}
109+
```
110+
111+
However, this gives us an error:
112+
113+
```text
114+
5:19: 7:6 error: closure may outlive the current function, but it
115+
borrows `x`, which is owned by the current function
116+
...
117+
5:19: 7:6 help: to force the closure to take ownership of `x` (and any other referenced variables),
118+
use the `move` keyword, as shown:
119+
thread::spawn(move || {
120+
println!("x is {}", x);
121+
});
122+
```
123+
124+
This is because by default closures capture variables by reference, and thus the
125+
closure only captures a _reference to `x`_. This is a problem, because the
126+
thread may outlive the scope of `x`, leading to a dangling pointer.
127+
128+
To fix this, we use a `move` closure as mentioned in the error message. `move`
129+
closures are explained in depth [here](closures.html#move-closures); basically
130+
they move variables from their environment into themselves. This means that `x`
131+
is now owned by the closure, and cannot be used in `main()` after the call to
132+
`spawn()`.
133+
134+
```rust
135+
use std::thread;
136+
137+
fn main() {
138+
let x = 1;
139+
thread::spawn(move || {
140+
println!("x is {}", x);
141+
});
142+
}
143+
```
144+
97145
Many languages have the ability to execute threads, but it's wildly unsafe.
98146
There are entire books about how to prevent errors that occur from shared
99147
mutable state. Rust helps out with its type system here as well, by preventing
@@ -145,23 +193,64 @@ This gives us an error:
145193
```
146194

147195
Rust knows this wouldn't be safe! If we had a reference to `data` in each
148-
thread, and the thread takes ownership of the reference, we'd have three
149-
owners!
196+
thread, and the thread takes ownership of the reference, we'd have three owners!
197+
`data` gets moved out of `main` in the first call to `spawn()`, so subsequent
198+
calls in the loop cannot use this variable.
199+
200+
So, we need some type that lets us have more than one owning reference to a
201+
value. Usually, we'd use `Rc<T>` for this, which is a reference counted type
202+
that provides shared ownership. It has some runtime bookkeeping that keeps track
203+
of the number of references to it, hence the "reference count" part of its name.
204+
205+
Calling `clone()` on an `Rc<T>` will return a new owned reference and bump the
206+
internal reference count. We create one of these for each thread:
150207

151-
So, we need some type that lets us have more than one reference to a value and
152-
that we can share between threads, that is it must implement `Sync`.
153208

154-
We'll use `Arc<T>`, Rust's standard atomic reference count type, which
155-
wraps a value up with some extra runtime bookkeeping which allows us to
156-
share the ownership of the value between multiple references at the same time.
209+
```ignore
210+
use std::thread;
211+
use std::time::Duration;
212+
use std::rc::Rc;
157213
158-
The bookkeeping consists of a count of how many of these references exist to
159-
the value, hence the reference count part of the name.
214+
fn main() {
215+
let mut data = Rc::new(vec![1, 2, 3]);
216+
217+
for i in 0..3 {
218+
// create a new owned reference
219+
let data_ref = data.clone();
220+
221+
// use it in a thread
222+
thread::spawn(move || {
223+
data_ref[i] += 1;
224+
});
225+
}
226+
227+
thread::sleep(Duration::from_millis(50));
228+
}
229+
```
230+
231+
This won't work, however, and will give us the error:
232+
233+
```text
234+
13:9: 13:22 error: the trait `core::marker::Send` is not
235+
implemented for the type `alloc::rc::Rc<collections::vec::Vec<i32>>`
236+
...
237+
13:9: 13:22 note: `alloc::rc::Rc<collections::vec::Vec<i32>>`
238+
cannot be sent between threads safely
239+
```
240+
241+
As the error message mentions, `Rc` cannot be sent between threads safely. This
242+
is because the internal reference count is not maintained in a thread safe
243+
matter and can have a data race.
244+
245+
To solve this, we'll use `Arc<T>`, Rust's standard atomic reference count type.
160246

161247
The Atomic part means `Arc<T>` can safely be accessed from multiple threads.
162248
To do this the compiler guarantees that mutations of the internal count use
163249
indivisible operations which can't have data races.
164250

251+
In essence, `Arc<T>` is a type that lets us share ownership of data _across
252+
threads_.
253+
165254

166255
```ignore
167256
use std::thread;
@@ -182,7 +271,7 @@ fn main() {
182271
}
183272
```
184273

185-
We now call `clone()` on our `Arc<T>`, which increases the internal count.
274+
Similarly to las time, we use `clone()` to create a new owned handle.
186275
This handle is then moved into the new thread.
187276

188277
And... still gives us an error.
@@ -193,14 +282,21 @@ And... still gives us an error.
193282
^~~~
194283
```
195284

196-
`Arc<T>` assumes one more property about its contents to ensure that it is safe
197-
to share across threads: it assumes its contents are `Sync`. This is true for
198-
our value if it's immutable, but we want to be able to mutate it, so we need
199-
something else to persuade the borrow checker we know what we're doing.
285+
`Arc<T> by default has immutable contents. It allows the _sharing_ of data
286+
between threads, but shared mutable data is unsafe and when threads are
287+
involved can cause data races!
288+
200289

201-
It looks like we need some type that allows us to safely mutate a shared value,
202-
for example a type that can ensure only one thread at a time is able to
203-
mutate the value inside it at any one time.
290+
Usually when we wish to make something in an immutable position mutable, we use
291+
`Cell<T>` or `RefCell<T>` which allow safe mutation via runtime checks or
292+
otherwise (see also: [Choosing Your Guarantees](choosing-your-guarantees.html)).
293+
However, similar to `Rc`, these are not thread safe. If we try using these, we
294+
will get an error about these types not being `Sync`, and the code will fail to
295+
compile.
296+
297+
It looks like we need some type that allows us to safely mutate a shared value
298+
across threads, for example a type that can ensure only one thread at a time is
299+
able to mutate the value inside it at any one time.
204300

205301
For that, we can use the `Mutex<T>` type!
206302

@@ -229,7 +325,17 @@ fn main() {
229325
Note that the value of `i` is bound (copied) to the closure and not shared
230326
among the threads.
231327

232-
Also note that [`lock`](../std/sync/struct.Mutex.html#method.lock) method of
328+
We're "locking" the mutex here. A mutex (short for "mutual exclusion"), as
329+
mentioned, only allows one thread at a time to access a value. When we wish to
330+
access the value, we use `lock()` on it. This will "lock" the mutex, and no
331+
other thread will be able to lock it (and hence, do anything with the value)
332+
until we're done with it. If a thread attempts to lock a mutex which is already
333+
locked, it will wait until the other thread releases the lock.
334+
335+
The lock "release" here is implicit; when the result of the lock (in this case,
336+
`data`) goes out of scope, the lock is automatically released.
337+
338+
Note that [`lock`](../std/sync/struct.Mutex.html#method.lock) method of
233339
[`Mutex`](../std/sync/struct.Mutex.html) has this signature:
234340

235341
```ignore

branches/beta/src/libsyntax/feature_gate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option<u32>, Status
199199
("associated_type_defaults", "1.2.0", Some(29661), Active),
200200

201201
// Allows macros to appear in the type position.
202-
("type_macros", "1.3.0", Some(27245), Active),
202+
("type_macros", "1.3.0", Some(27336), Active),
203203

204204
// allow `repr(simd)`, and importing the various simd intrinsics
205205
("repr_simd", "1.4.0", Some(27731), Active),

branches/beta/src/libsyntax_ext/deriving/generic/mod.rs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,6 @@ use syntax::ptr::P;
209209

210210
use self::ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty};
211211

212-
use deriving;
213-
214212
pub mod ty;
215213

216214
pub struct TraitDef<'a> {
@@ -383,6 +381,22 @@ fn find_type_parameters(ty: &ast::Ty, ty_param_names: &[ast::Name]) -> Vec<P<ast
383381
visitor.types
384382
}
385383

384+
/// Replacement for expr_unreachable which generates intrinsics::unreachable()
385+
/// instead of unreachable!()
386+
fn expr_unreachable_intrinsic(cx: &ExtCtxt, sp: Span) -> P<Expr> {
387+
let path = cx.std_path(&["intrinsics", "unreachable"]);
388+
let call = cx.expr_call_global(
389+
sp, path, vec![]);
390+
let unreachable = cx.expr_block(P(ast::Block {
391+
stmts: vec![],
392+
expr: Some(call),
393+
id: ast::DUMMY_NODE_ID,
394+
rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
395+
span: sp }));
396+
397+
unreachable
398+
}
399+
386400
impl<'a> TraitDef<'a> {
387401
pub fn expand(&self,
388402
cx: &mut ExtCtxt,
@@ -1265,11 +1279,15 @@ impl<'a> MethodDef<'a> {
12651279

12661280
let mut first_ident = None;
12671281
for (&ident, self_arg) in vi_idents.iter().zip(&self_args) {
1268-
let self_addr = cx.expr_addr_of(sp, self_arg.clone());
1269-
let variant_value = deriving::call_intrinsic(cx,
1270-
sp,
1271-
"discriminant_value",
1272-
vec![self_addr]);
1282+
let path = cx.std_path(&["intrinsics", "discriminant_value"]);
1283+
let call = cx.expr_call_global(
1284+
sp, path, vec![cx.expr_addr_of(sp, self_arg.clone())]);
1285+
let variant_value = cx.expr_block(P(ast::Block {
1286+
stmts: vec![],
1287+
expr: Some(call),
1288+
id: ast::DUMMY_NODE_ID,
1289+
rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
1290+
span: sp }));
12731291

12741292
let target_ty = cx.ty_ident(sp, cx.ident_of(target_type_name));
12751293
let variant_disr = cx.expr_cast(sp, variant_value, target_ty);
@@ -1297,9 +1315,7 @@ impl<'a> MethodDef<'a> {
12971315
//Since we know that all the arguments will match if we reach the match expression we
12981316
//add the unreachable intrinsics as the result of the catch all which should help llvm
12991317
//in optimizing it
1300-
match_arms.push(cx.arm(sp,
1301-
vec![cx.pat_wild(sp)],
1302-
deriving::call_intrinsic(cx, sp, "unreachable", vec![])));
1318+
match_arms.push(cx.arm(sp, vec![cx.pat_wild(sp)], expr_unreachable_intrinsic(cx, sp)));
13031319

13041320
// Final wrinkle: the self_args are expressions that deref
13051321
// down to desired l-values, but we cannot actually deref
@@ -1375,7 +1391,7 @@ impl<'a> MethodDef<'a> {
13751391
// derive Debug on such a type could here generate code
13761392
// that needs the feature gate enabled.)
13771393

1378-
deriving::call_intrinsic(cx, sp, "unreachable", vec![])
1394+
expr_unreachable_intrinsic(cx, sp)
13791395
}
13801396
else {
13811397

branches/beta/src/libsyntax_ext/deriving/hash.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,15 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
8181

8282
let fields = match *substr.fields {
8383
Struct(_, ref fs) => fs,
84-
EnumMatching(_, _, ref fs) => {
85-
let variant_value = deriving::call_intrinsic(cx,
86-
trait_span,
87-
"discriminant_value",
88-
vec![cx.expr_self(trait_span)]);
84+
EnumMatching(index, variant, ref fs) => {
85+
// Determine the discriminant. We will feed this value to the byte
86+
// iteration function.
87+
let discriminant = match variant.node.disr_expr {
88+
Some(ref d) => d.clone(),
89+
None => cx.expr_usize(trait_span, index)
90+
};
8991

90-
stmts.push(call_hash(trait_span, variant_value));
92+
stmts.push(call_hash(trait_span, discriminant));
9193

9294
fs
9395
}

branches/beta/src/libsyntax_ext/deriving/mod.rs

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use syntax::ext::build::AstBuilder;
1818
use syntax::feature_gate;
1919
use syntax::codemap::Span;
2020
use syntax::parse::token::{intern, intern_and_get_ident};
21-
use syntax::ptr::P;
2221

2322
macro_rules! pathvec {
2423
($($x:ident)::+) => (
@@ -272,19 +271,3 @@ fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
272271
typaram
273272
}
274273

275-
/// Constructs an expression that calls an intrinsic
276-
fn call_intrinsic(cx: &ExtCtxt,
277-
span: Span,
278-
intrinsic: &str,
279-
args: Vec<P<ast::Expr>>) -> P<ast::Expr> {
280-
let path = cx.std_path(&["intrinsics", intrinsic]);
281-
let call = cx.expr_call_global(span, path, args);
282-
283-
cx.expr_block(P(ast::Block {
284-
stmts: vec![],
285-
expr: Some(call),
286-
id: ast::DUMMY_NODE_ID,
287-
rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
288-
span: span }))
289-
}
290-

branches/beta/src/test/compile-fail/type-macros-fail.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ macro_rules! Id {
1414

1515
struct Foo<T> {
1616
x: Id!(T)
17-
//~^ ERROR: type macros are experimental (see issue #27245)
17+
//~^ ERROR: type macros are experimental (see issue #27336)
1818
}
1919

2020
fn main() {

0 commit comments

Comments
 (0)