Skip to content

Commit 8e28520

Browse files
committed
auto merge of #12686 : FlaPer87/rust/shared, r=nikomatsakis
`Share` implies that all *reachable* content is *threadsafe*. Threadsafe is defined as "exposing no operation that permits a data race if multiple threads have access to a &T pointer simultaneously". (NB: the type system should guarantee that if you have access to memory via a &T pointer, the only other way to gain access to that memory is through another &T pointer)... Fixes #11781 cc #12577 What this PR will do ================ - [x] Add Share kind and - [x] Replace usages of Freeze with Share in bounds. - [x] Add Unsafe<T> #12577 - [x] Forbid taking the address of a immutable static item with `Unsafe<T>` interior What's left to do in a separate PR (after the snapshot)? =========================================== - Remove `Freeze` completely
2 parents 95ee0a0 + 7b19574 commit 8e28520

40 files changed

+500
-267
lines changed

src/doc/guide-unsafe.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -595,10 +595,10 @@ Other features provided by lang items include:
595595
- stack unwinding and general failure; the `eh_personality`, `fail_`
596596
and `fail_bounds_checks` lang items.
597597
- the traits in `std::kinds` used to indicate types that satisfy
598-
various kinds; lang items `send`, `freeze` and `pod`.
598+
various kinds; lang items `send`, `share` and `pod`.
599599
- the marker types and variance indicators found in
600600
`std::kinds::markers`; lang items `covariant_type`,
601-
`contravariant_lifetime`, `no_freeze_bound`, etc.
601+
`contravariant_lifetime`, `no_share_bound`, etc.
602602

603603
Lang items are loaded lazily by the compiler; e.g. if one never uses
604604
`~` then there is no need to define functions for `exchange_malloc`

src/doc/tutorial.md

+4
Original file line numberDiff line numberDiff line change
@@ -2095,6 +2095,10 @@ and may not be overridden:
20952095
Types are sendable
20962096
unless they contain managed boxes, managed closures, or references.
20972097
2098+
* `Share` - Types that are *threadsafe*
2099+
These are types that are safe to be used across several threads with access to
2100+
a `&T` pointer. `MutexArc` is an example of a *sharable* type with internal mutable data.
2101+
20982102
* `Freeze` - Constant (immutable) types.
20992103
These are types that do not contain anything intrinsically mutable.
21002104
Intrinsically mutable values include `Cell` in the standard library.

src/librustc/metadata/tydecode.rs

+3
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,9 @@ fn parse_bounds(st: &mut PState, conv: conv_did) -> ty::ParamBounds {
603603
'P' => {
604604
param_bounds.builtin_bounds.add(ty::BoundPod);
605605
}
606+
'T' => {
607+
param_bounds.builtin_bounds.add(ty::BoundShare);
608+
}
606609
'I' => {
607610
param_bounds.trait_bounds.push(@parse_trait_ref(st, |x,y| conv(x,y)));
608611
}

src/librustc/metadata/tyencode.rs

+1
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,7 @@ fn enc_bounds(w: &mut MemWriter, cx: &ctxt, bs: &ty::ParamBounds) {
410410
ty::BoundStatic => mywrite!(w, "O"),
411411
ty::BoundSized => mywrite!(w, "Z"),
412412
ty::BoundPod => mywrite!(w, "P"),
413+
ty::BoundShare => mywrite!(w, "T"),
413414
}
414415
}
415416

src/librustc/middle/borrowck/check_loans.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -518,11 +518,11 @@ impl<'a> CheckLoanCtxt<'a> {
518518
expr: &ast::Expr,
519519
cmt: mc::cmt)
520520
-> bool {
521-
match cmt.freely_aliasable() {
521+
match cmt.freely_aliasable(this.tcx()) {
522522
None => {
523523
return true;
524524
}
525-
Some(mc::AliasableStaticMut) => {
525+
Some(mc::AliasableStaticMut(..)) => {
526526
return true;
527527
}
528528
Some(cause) => {

src/librustc/middle/borrowck/gather_loans/mod.rs

+71-47
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,12 @@ impl<'a> visit::Visitor<()> for GatherLoanCtxt<'a> {
8282
fn visit_block(&mut self, b: &Block, _: ()) {
8383
gather_loans_in_block(self, b);
8484
}
85-
fn visit_fn(&mut self, fk: &FnKind, fd: &FnDecl, b: &Block,
86-
s: Span, n: NodeId, _: ()) {
87-
gather_loans_in_fn(self, fk, fd, b, s, n);
88-
}
85+
86+
/// Do not visit closures or fn items here, the outer loop in
87+
/// borrowck/mod will visit them for us in turn.
88+
fn visit_fn(&mut self, _: &FnKind, _: &FnDecl, _: &Block,
89+
_: Span, _: NodeId, _: ()) {}
90+
8991
fn visit_stmt(&mut self, s: &Stmt, _: ()) {
9092
visit::walk_stmt(self, s, ());
9193
}
@@ -99,10 +101,20 @@ impl<'a> visit::Visitor<()> for GatherLoanCtxt<'a> {
99101
// #7740: Do not visit items here, not even fn items nor methods
100102
// of impl items; the outer loop in borrowck/mod will visit them
101103
// for us in turn. Thus override visit_item's walk with a no-op.
102-
fn visit_item(&mut self, _: &ast::Item, _: ()) { }
104+
fn visit_item(&mut self, _: &ast::Item, _: ()) {}
105+
}
106+
107+
fn add_pat_to_id_range(this: &mut GatherLoanCtxt,
108+
p: &ast::Pat) {
109+
// NB: This visitor function just adds the pat ids into the id
110+
// range. We gather loans that occur in patterns using the
111+
// `gather_pat()` method below. Eventually these two should be
112+
// brought together.
113+
this.id_range.add(p.id);
114+
visit::walk_pat(this, p, ());
103115
}
104116

105-
pub fn gather_loans(bccx: &BorrowckCtxt, decl: &ast::FnDecl, body: &ast::Block)
117+
pub fn gather_loans_in_fn(bccx: &BorrowckCtxt, decl: &ast::FnDecl, body: &ast::Block)
106118
-> (IdRange, Vec<Loan>, move_data::MoveData) {
107119
let mut glcx = GatherLoanCtxt {
108120
bccx: bccx,
@@ -119,27 +131,6 @@ pub fn gather_loans(bccx: &BorrowckCtxt, decl: &ast::FnDecl, body: &ast::Block)
119131
(id_range, all_loans, move_data)
120132
}
121133

122-
fn add_pat_to_id_range(this: &mut GatherLoanCtxt,
123-
p: &ast::Pat) {
124-
// NB: This visitor function just adds the pat ids into the id
125-
// range. We gather loans that occur in patterns using the
126-
// `gather_pat()` method below. Eventually these two should be
127-
// brought together.
128-
this.id_range.add(p.id);
129-
visit::walk_pat(this, p, ());
130-
}
131-
132-
fn gather_loans_in_fn(_v: &mut GatherLoanCtxt,
133-
_fk: &FnKind,
134-
_decl: &ast::FnDecl,
135-
_body: &ast::Block,
136-
_sp: Span,
137-
_id: ast::NodeId) {
138-
// Do not visit closures or fn items here, the outer loop in
139-
// borrowck/mod will visit them for us in turn.
140-
return;
141-
}
142-
143134
fn gather_loans_in_block(this: &mut GatherLoanCtxt,
144135
blk: &ast::Block) {
145136
this.id_range.add(blk.id);
@@ -171,6 +162,28 @@ fn gather_loans_in_local(this: &mut GatherLoanCtxt,
171162
visit::walk_local(this, local, ());
172163
}
173164

165+
pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt, expr: &ast::Expr) {
166+
167+
debug!("gather_loans_in_item(expr={})", expr.repr(bccx.tcx));
168+
169+
let mut glcx = GatherLoanCtxt {
170+
bccx: bccx,
171+
id_range: IdRange::max(),
172+
all_loans: Vec::new(),
173+
item_ub: expr.id,
174+
repeating_ids: vec!(expr.id),
175+
move_data: MoveData::new()
176+
};
177+
178+
// FIXME #13005 This should also walk the
179+
// expression.
180+
match expr.node {
181+
ast::ExprAddrOf(..) => {
182+
glcx.visit_expr(expr, ());
183+
}
184+
_ => {}
185+
}
186+
}
174187

175188
fn gather_loans_in_expr(this: &mut GatherLoanCtxt,
176189
ex: &ast::Expr) {
@@ -673,34 +686,45 @@ impl<'a> GatherLoanCtxt<'a> {
673686
-> Result<(),()> {
674687
//! Implements the A-* rules in doc.rs.
675688
676-
match req_kind {
677-
ty::ImmBorrow => {
689+
match (cmt.freely_aliasable(bccx.tcx), req_kind) {
690+
(None, _) => {
691+
/* Uniquely accessible path -- OK for `&` and `&mut` */
678692
Ok(())
679693
}
680-
681-
ty::UniqueImmBorrow | ty::MutBorrow => {
682-
// Check for those cases where we cannot control
683-
// the aliasing and make sure that we are not
684-
// being asked to.
685-
match cmt.freely_aliasable() {
686-
None => {
687-
Ok(())
694+
(Some(mc::AliasableStatic(safety)), ty::ImmBorrow) => {
695+
// Borrow of an immutable static item:
696+
match safety {
697+
mc::InteriorUnsafe => {
698+
// If the static item contains an Unsafe<T>, it has interior mutability.
699+
// In such cases, we cannot permit it to be borrowed, because the
700+
// static item resides in immutable memory and mutating it would
701+
// cause segfaults.
702+
bccx.tcx.sess.span_err(borrow_span,
703+
format!("borrow of immutable static items with \
704+
unsafe interior is not allowed"));
705+
Err(())
688706
}
689-
Some(mc::AliasableStaticMut) => {
690-
// This is nasty, but we ignore the
691-
// aliasing rules if the data is based in
692-
// a `static mut`, since those are always
693-
// unsafe. At your own peril and all that.
707+
mc::InteriorSafe => {
708+
// Immutable static can be borrowed, no problem.
694709
Ok(())
695710
}
696-
Some(alias_cause) => {
697-
bccx.report_aliasability_violation(
711+
}
712+
}
713+
(Some(mc::AliasableStaticMut(..)), _) => {
714+
// Even touching a static mut is considered unsafe. We assume the
715+
// user knows what they're doing in these cases.
716+
Ok(())
717+
}
718+
(Some(alias_cause), ty::UniqueImmBorrow) |
719+
(Some(alias_cause), ty::MutBorrow) => {
720+
bccx.report_aliasability_violation(
698721
borrow_span,
699722
BorrowViolation(loan_cause),
700723
alias_cause);
701-
Err(())
702-
}
703-
}
724+
Err(())
725+
}
726+
(_, _) => {
727+
Ok(())
704728
}
705729
}
706730
}

src/librustc/middle/borrowck/mod.rs

+22-3
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ impl<'a> Visitor<()> for BorrowckCtxt<'a> {
6969
b: &Block, s: Span, n: NodeId, _: ()) {
7070
borrowck_fn(self, fk, fd, b, s, n);
7171
}
72+
73+
fn visit_item(&mut self, item: &ast::Item, _: ()) {
74+
borrowck_item(self, item);
75+
}
7276
}
7377

7478
pub fn check_crate(tcx: &ty::ctxt,
@@ -117,6 +121,21 @@ pub fn check_crate(tcx: &ty::ctxt,
117121
}
118122
}
119123

124+
fn borrowck_item(this: &mut BorrowckCtxt, item: &ast::Item) {
125+
// Gather loans for items. Note that we don't need
126+
// to check loans for single expressions. The check
127+
// loan step is intended for things that have a data
128+
// flow dependent conditions.
129+
match item.node {
130+
ast::ItemStatic(_, _, ex) => {
131+
gather_loans::gather_loans_in_static_initializer(this, ex);
132+
}
133+
_ => {
134+
visit::walk_item(this, item, ());
135+
}
136+
}
137+
}
138+
120139
fn borrowck_fn(this: &mut BorrowckCtxt,
121140
fk: &FnKind,
122141
decl: &ast::FnDecl,
@@ -127,7 +146,7 @@ fn borrowck_fn(this: &mut BorrowckCtxt,
127146

128147
// Check the body of fn items.
129148
let (id_range, all_loans, move_data) =
130-
gather_loans::gather_loans(this, decl, body);
149+
gather_loans::gather_loans_in_fn(this, decl, body);
131150
let mut loan_dfcx =
132151
DataFlowContext::new(this.tcx,
133152
this.method_map,
@@ -715,8 +734,8 @@ impl<'a> BorrowckCtxt<'a> {
715734
span,
716735
format!("{} in an aliasable location", prefix));
717736
}
718-
mc::AliasableStatic |
719-
mc::AliasableStaticMut => {
737+
mc::AliasableStatic(..) |
738+
mc::AliasableStaticMut(..) => {
720739
self.tcx.sess.span_err(
721740
span,
722741
format!("{} in a static location", prefix));

src/librustc/middle/check_static.rs

+4-21
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@
1818
// - For each *immutable* static item, it checks that its **value**:
1919
// - doesn't own owned, managed pointers
2020
// - doesn't contain a struct literal or a call to an enum variant / struct constructor where
21-
// - the type of the struct/enum is not freeze
2221
// - the type of the struct/enum has a dtor
22+
//
23+
// Rules Enforced Elsewhere:
24+
// - It's not possible to take the address of a static item with unsafe interior. This is enforced
25+
// by borrowck::gather_loans
2326

2427
use middle::ty;
2528

@@ -121,21 +124,6 @@ impl<'a> Visitor<bool> for CheckStaticVisitor<'a> {
121124
self.tcx.sess.span_err(e.span,
122125
"static items are not allowed to have owned pointers");
123126
}
124-
ast::ExprProc(..) => {
125-
self.report_error(e.span,
126-
Some(~"immutable static items must be `Freeze`"));
127-
return;
128-
}
129-
ast::ExprAddrOf(mutability, _) => {
130-
match mutability {
131-
ast::MutMutable => {
132-
self.report_error(e.span,
133-
Some(~"immutable static items must be `Freeze`"));
134-
return;
135-
}
136-
_ => {}
137-
}
138-
}
139127
_ => {
140128
let node_ty = ty::node_id_to_type(self.tcx, e.id);
141129

@@ -147,11 +135,6 @@ impl<'a> Visitor<bool> for CheckStaticVisitor<'a> {
147135
Some(~"static items are not allowed to have destructors"));
148136
return;
149137
}
150-
if Some(did) == self.tcx.lang_items.no_freeze_bound() {
151-
self.report_error(e.span,
152-
Some(~"immutable static items must be `Freeze`"));
153-
return;
154-
}
155138
}
156139
_ => {}
157140
}

src/librustc/middle/lang_items.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
use driver::session::Session;
2424
use metadata::csearch::each_lang_item;
25-
use middle::ty::{BuiltinBound, BoundFreeze, BoundPod, BoundSend, BoundSized};
25+
use middle::ty;
2626
use syntax::ast;
2727
use syntax::ast_util::local_def;
2828
use syntax::attr::AttrMetaMethods;
@@ -82,15 +82,17 @@ impl LanguageItems {
8282
}
8383
}
8484

85-
pub fn to_builtin_kind(&self, id: ast::DefId) -> Option<BuiltinBound> {
85+
pub fn to_builtin_kind(&self, id: ast::DefId) -> Option<ty::BuiltinBound> {
8686
if Some(id) == self.freeze_trait() {
87-
Some(BoundFreeze)
87+
Some(ty::BoundFreeze)
8888
} else if Some(id) == self.send_trait() {
89-
Some(BoundSend)
89+
Some(ty::BoundSend)
9090
} else if Some(id) == self.sized_trait() {
91-
Some(BoundSized)
91+
Some(ty::BoundSized)
9292
} else if Some(id) == self.pod_trait() {
93-
Some(BoundPod)
93+
Some(ty::BoundPod)
94+
} else if Some(id) == self.share_trait() {
95+
Some(ty::BoundShare)
9496
} else {
9597
None
9698
}
@@ -213,6 +215,7 @@ lets_do_this! {
213215
SendTraitLangItem, "send", send_trait;
214216
SizedTraitLangItem, "sized", sized_trait;
215217
PodTraitLangItem, "pod", pod_trait;
218+
ShareTraitLangItem, "share", share_trait;
216219

217220
DropTraitLangItem, "drop", drop_trait;
218221

@@ -230,6 +233,8 @@ lets_do_this! {
230233
ShrTraitLangItem, "shr", shr_trait;
231234
IndexTraitLangItem, "index", index_trait;
232235

236+
UnsafeTypeLangItem, "unsafe", unsafe_type;
237+
233238
DerefTraitLangItem, "deref", deref_trait;
234239
DerefMutTraitLangItem, "deref_mut", deref_mut_trait;
235240

@@ -274,5 +279,6 @@ lets_do_this! {
274279
NoFreezeItem, "no_freeze_bound", no_freeze_bound;
275280
NoSendItem, "no_send_bound", no_send_bound;
276281
NoPodItem, "no_pod_bound", no_pod_bound;
282+
NoShareItem, "no_share_bound", no_share_bound;
277283
ManagedItem, "managed_bound", managed_bound;
278284
}

0 commit comments

Comments
 (0)