Skip to content

Commit d4fee24

Browse files
committed
librustc: Forbid destructors from being attached to any structs that might contain non-Owned fields. r=nmatsakis
1 parent 5726fd4 commit d4fee24

40 files changed

+236
-47
lines changed

src/libcore/condition.rs

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ struct Guard<T, U> {
8484
cond: &'self Condition/&self<T, U>
8585
}
8686

87+
#[unsafe_destructor]
8788
impl<T, U> Drop for Guard/&self<T, U> {
8889
fn finalize(&self) {
8990
unsafe {

src/libcore/io.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -1230,15 +1230,17 @@ pub mod fsync {
12301230
arg: Arg<t>,
12311231
}
12321232

1233+
#[unsafe_destructor]
12331234
impl<T:Copy> Drop for Res<T> {
12341235
fn finalize(&self) {
1235-
match self.arg.opt_level {
1236-
None => (),
1237-
Some(level) => {
1238-
// fail hard if not succesful
1239-
fail_unless!(((self.arg.fsync_fn)(self.arg.val, level) != -1));
1236+
match self.arg.opt_level {
1237+
None => (),
1238+
Some(level) => {
1239+
// fail hard if not succesful
1240+
fail_unless!(((self.arg.fsync_fn)(self.arg.val, level)
1241+
!= -1));
1242+
}
12401243
}
1241-
}
12421244
}
12431245
}
12441246

src/libcore/option.rs

+1
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,7 @@ fn test_unwrap_resource() {
514514
i: @mut int,
515515
}
516516

517+
#[unsafe_destructor]
517518
impl ::ops::Drop for R {
518519
fn finalize(&self) { *(self.i) += 1; }
519520
}

src/libcore/pipes.rs

+10-6
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ struct BufferResource<T> {
350350
351351
}
352352
353+
#[unsafe_destructor]
353354
impl<T> ::ops::Drop for BufferResource<T> {
354355
fn finalize(&self) {
355356
unsafe {
@@ -445,16 +446,17 @@ pub fn try_recv<T:Owned,Tbuffer:Owned>(p: RecvPacketBuffered<T, Tbuffer>)
445446
let p_ = p.unwrap();
446447
let p = unsafe { &*p_ };
447448
449+
#[unsafe_destructor]
448450
struct DropState {
449451
p: &'self PacketHeader,
450452
451453
drop {
452-
if task::failing() {
453-
self.p.state = Terminated;
454-
let old_task = swap_task(&mut self.p.blocked_task,
455-
ptr::null());
456-
if !old_task.is_null() {
457-
unsafe {
454+
unsafe {
455+
if task::failing() {
456+
self.p.state = Terminated;
457+
let old_task = swap_task(&mut self.p.blocked_task,
458+
ptr::null());
459+
if !old_task.is_null() {
458460
rustrt::rust_task_deref(old_task);
459461
}
460462
}
@@ -773,6 +775,7 @@ pub struct SendPacketBuffered<T, Tbuffer> {
773775
mut buffer: Option<BufferResource<Tbuffer>>,
774776
}
775777
778+
#[unsafe_destructor]
776779
impl<T:Owned,Tbuffer:Owned> ::ops::Drop for SendPacketBuffered<T,Tbuffer> {
777780
fn finalize(&self) {
778781
//if self.p != none {
@@ -842,6 +845,7 @@ pub struct RecvPacketBuffered<T, Tbuffer> {
842845
mut buffer: Option<BufferResource<Tbuffer>>,
843846
}
844847
848+
#[unsafe_destructor]
845849
impl<T:Owned,Tbuffer:Owned> ::ops::Drop for RecvPacketBuffered<T,Tbuffer> {
846850
fn finalize(&self) {
847851
//if self.p != none {

src/libcore/unstable.rs

+1
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ struct ArcDestruct<T> {
118118
mut data: *libc::c_void,
119119
}
120120

121+
#[unsafe_destructor]
121122
impl<T> Drop for ArcDestruct<T>{
122123
fn finalize(&self) {
123124
unsafe {

src/libcore/unstable/finally.rs

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct Finallyalizer {
4545
dtor: &'self fn()
4646
}
4747

48+
#[unsafe_destructor]
4849
impl Drop for Finallyalizer/&self {
4950
fn finalize(&self) {
5051
(self.dtor)();

src/librustc/middle/kind.rs

+94-5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use core::str;
2222
use core::vec;
2323
use std::oldmap::HashMap;
2424
use syntax::ast::*;
25+
use syntax::attr::attrs_contains_name;
2526
use syntax::codemap::{span, spanned};
2627
use syntax::print::pprust::expr_to_str;
2728
use syntax::{visit, ast_util};
@@ -55,6 +56,8 @@ use syntax::{visit, ast_util};
5556
// primitives in the stdlib are explicitly annotated to only take sendable
5657
// types.
5758

59+
use core::hashmap::linear::LinearSet;
60+
5861
pub const try_adding: &'static str = "Try adding a move";
5962

6063
pub type rval_map = HashMap<node_id, ()>;
@@ -63,7 +66,7 @@ pub struct Context {
6366
tcx: ty::ctxt,
6467
method_map: typeck::method_map,
6568
last_use_map: liveness::last_use_map,
66-
current_item: node_id
69+
current_item: node_id,
6770
}
6871

6972
pub fn check_crate(tcx: ty::ctxt,
@@ -74,16 +77,15 @@ pub fn check_crate(tcx: ty::ctxt,
7477
tcx: tcx,
7578
method_map: method_map,
7679
last_use_map: last_use_map,
77-
current_item: -1
80+
current_item: -1,
7881
};
7982
let visit = visit::mk_vt(@visit::Visitor {
8083
visit_arm: check_arm,
8184
visit_expr: check_expr,
8285
visit_fn: check_fn,
8386
visit_ty: check_ty,
84-
visit_item: |i, cx, v| {
85-
visit::visit_item(i, Context { current_item: i.id,.. cx }, v);
86-
},
87+
visit_item: check_item,
88+
visit_block: check_block,
8789
.. *visit::default_visitor()
8890
});
8991
visit::visit_crate(*crate, ctx, visit);
@@ -92,6 +94,93 @@ pub fn check_crate(tcx: ty::ctxt,
9294

9395
type check_fn = @fn(Context, @freevar_entry);
9496

97+
fn check_struct_safe_for_destructor(cx: Context,
98+
span: span,
99+
struct_did: def_id) {
100+
let struct_tpt = ty::lookup_item_type(cx.tcx, struct_did);
101+
if struct_tpt.bounds.len() == 0 {
102+
let struct_ty = ty::mk_struct(cx.tcx, struct_did, ty::substs {
103+
self_r: None,
104+
self_ty: None,
105+
tps: ~[]
106+
});
107+
if !ty::type_is_owned(cx.tcx, struct_ty) {
108+
cx.tcx.sess.span_err(span,
109+
~"cannot implement a destructor on a struct \
110+
that is not Owned");
111+
cx.tcx.sess.span_note(span,
112+
~"use \"#[unsafe_destructor]\" on the \
113+
implementation to force the compiler to \
114+
allow this");
115+
}
116+
} else {
117+
cx.tcx.sess.span_err(span,
118+
~"cannot implement a destructor on a struct \
119+
with type parameters");
120+
cx.tcx.sess.span_note(span,
121+
~"use \"#[unsafe_destructor]\" on the \
122+
implementation to force the compiler to \
123+
allow this");
124+
}
125+
}
126+
127+
fn check_block(block: &blk, cx: Context, visitor: visit::vt<Context>) {
128+
visit::visit_block(block, cx, visitor);
129+
}
130+
131+
fn check_item(item: @item, cx: Context, visitor: visit::vt<Context>) {
132+
// If this is a destructor, check kinds.
133+
if !attrs_contains_name(item.attrs, "unsafe_destructor") {
134+
match item.node {
135+
item_impl(_, Some(trait_ref), self_type, _) => {
136+
match cx.tcx.def_map.find(&trait_ref.ref_id) {
137+
None => cx.tcx.sess.bug(~"trait ref not in def map!"),
138+
Some(trait_def) => {
139+
let trait_def_id = ast_util::def_id_of_def(trait_def);
140+
if cx.tcx.lang_items.drop_trait() == trait_def_id {
141+
// Yes, it's a destructor.
142+
match self_type.node {
143+
ty_path(_, path_node_id) => {
144+
let struct_def = cx.tcx.def_map.get(
145+
&path_node_id);
146+
let struct_did =
147+
ast_util::def_id_of_def(struct_def);
148+
check_struct_safe_for_destructor(
149+
cx,
150+
self_type.span,
151+
struct_did);
152+
}
153+
_ => {
154+
cx.tcx.sess.span_bug(self_type.span,
155+
~"the self type for \
156+
the Drop trait \
157+
impl is not a \
158+
path");
159+
}
160+
}
161+
}
162+
}
163+
}
164+
}
165+
item_struct(struct_def, _) => {
166+
match struct_def.dtor {
167+
None => {}
168+
Some(ref dtor) => {
169+
let struct_did = def_id { crate: 0, node: item.id };
170+
check_struct_safe_for_destructor(cx,
171+
dtor.span,
172+
struct_did);
173+
}
174+
}
175+
}
176+
_ => {}
177+
}
178+
}
179+
180+
let cx = Context { current_item: item.id, ..cx };
181+
visit::visit_item(item, cx, visitor);
182+
}
183+
95184
// Yields the appropriate function to check the kind of closed over
96185
// variables. `id` is the node_id for some expression that creates the
97186
// closure.

src/librustc/middle/trans/base.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,14 @@ pub struct icx_popper {
8888
ccx: @CrateContext,
8989
}
9090

91+
#[unsafe_destructor]
9192
impl Drop for icx_popper {
9293
fn finalize(&self) {
93-
if self.ccx.sess.count_llvm_insns() {
94-
self.ccx.stats.llvm_insn_ctxt.pop();
95-
}
94+
unsafe {
95+
if self.ccx.sess.count_llvm_insns() {
96+
self.ccx.stats.llvm_insn_ctxt.pop();
97+
}
98+
}
9699
}
97100
}
98101

src/libstd/arena.rs

+1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ pub struct Arena {
8888
priv mut chunks: @List<Chunk>,
8989
}
9090

91+
#[unsafe_destructor]
9192
impl Drop for Arena {
9293
fn finalize(&self) {
9394
unsafe {

src/libstd/c_vec.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,14 @@ struct DtorRes {
5454
dtor: Option<@fn()>,
5555
}
5656

57+
#[unsafe_destructor]
5758
impl Drop for DtorRes {
5859
fn finalize(&self) {
59-
match self.dtor {
60-
option::None => (),
61-
option::Some(f) => f()
60+
unsafe {
61+
match self.dtor {
62+
option::None => (),
63+
option::Some(f) => f()
64+
}
6265
}
6366
}
6467
}

src/libstd/future.rs

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ pub struct Future<A> {
3535

3636
// FIXME(#2829) -- futures should not be copyable, because they close
3737
// over ~fn's that have pipes and so forth within!
38+
#[unsafe_destructor]
3839
impl<A> Drop for Future<A> {
3940
fn finalize(&self) {}
4041
}

src/libstd/net_tcp.rs

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ pub struct TcpSocket {
5555
socket_data: @TcpSocketData,
5656
}
5757

58+
#[unsafe_destructor]
5859
impl Drop for TcpSocket {
5960
fn finalize(&self) {
6061
unsafe {

src/libstd/sort.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1190,6 +1190,7 @@ mod big_tests {
11901190
key: &'self fn(@uint),
11911191
}
11921192
1193+
#[unsafe_destructor]
11931194
impl Drop for LVal/&self {
11941195
fn finalize(&self) {
11951196
let x = unsafe { task::local_data::local_data_get(self.key) };

src/libstd/sync.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,12 @@ type SemRelease = SemReleaseGeneric<'self, ()>;
167167
type SemAndSignalRelease = SemReleaseGeneric<'self, ~[Waitqueue]>;
168168
struct SemReleaseGeneric<Q> { sem: &'self Sem<Q> }
169169

170+
#[unsafe_destructor]
170171
impl<Q:Owned> Drop for SemReleaseGeneric/&self<Q> {
171172
fn finalize(&self) {
172-
self.sem.release();
173+
unsafe {
174+
self.sem.release();
175+
}
173176
}
174177
}
175178

@@ -189,6 +192,7 @@ fn SemAndSignalRelease(sem: &'r Sem<~[Waitqueue]>)
189192
/// A mechanism for atomic-unlock-and-deschedule blocking and signalling.
190193
pub struct Condvar { priv sem: &'self Sem<~[Waitqueue]> }
191194

195+
#[unsafe_destructor]
192196
impl Drop for Condvar/&self { fn finalize(&self) {} }
193197

194198
pub impl Condvar/&self {
@@ -261,6 +265,7 @@ pub impl Condvar/&self {
261265
sem: &'self Sem<~[Waitqueue]>,
262266
}
263267

268+
#[unsafe_destructor]
264269
impl Drop for SemAndSignalReacquire/&self {
265270
fn finalize(&self) {
266271
unsafe {
@@ -613,6 +618,7 @@ struct RWlockReleaseRead {
613618
lock: &'self RWlock,
614619
}
615620
621+
#[unsafe_destructor]
616622
impl Drop for RWlockReleaseRead/&self {
617623
fn finalize(&self) {
618624
unsafe {
@@ -643,10 +649,12 @@ fn RWlockReleaseRead(lock: &'r RWlock) -> RWlockReleaseRead/&r {
643649
644650
// FIXME(#3588) should go inside of downgrade()
645651
#[doc(hidden)]
652+
#[unsafe_destructor]
646653
struct RWlockReleaseDowngrade {
647654
lock: &'self RWlock,
648655
}
649656
657+
#[unsafe_destructor]
650658
impl Drop for RWlockReleaseDowngrade/&self {
651659
fn finalize(&self) {
652660
unsafe {
@@ -685,10 +693,12 @@ fn RWlockReleaseDowngrade(lock: &'r RWlock) -> RWlockReleaseDowngrade/&r {
685693
686694
/// The "write permission" token used for rwlock.write_downgrade().
687695
pub struct RWlockWriteMode { priv lock: &'self RWlock }
696+
#[unsafe_destructor]
688697
impl Drop for RWlockWriteMode/&self { fn finalize(&self) {} }
689698
690699
/// The "read permission" token used for rwlock.write_downgrade().
691700
pub struct RWlockReadMode { priv lock: &'self RWlock }
701+
#[unsafe_destructor]
692702
impl Drop for RWlockReadMode/&self { fn finalize(&self) {} }
693703
694704
pub impl RWlockWriteMode/&self {

src/libstd/task_pool.rs

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub struct TaskPool<T> {
2828

2929
}
3030

31+
#[unsafe_destructor]
3132
impl<T> Drop for TaskPool<T> {
3233
fn finalize(&self) {
3334
for self.channels.each |channel| {

src/libsyntax/parse/parser.rs

+1
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ pub struct Parser {
268268

269269
}
270270

271+
#[unsafe_destructor]
271272
impl Drop for Parser {
272273
/* do not copy the parser; its state is tied to outside state */
273274
fn finalize(&self) {}

src/test/auxiliary/issue-2526.rs

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ struct arc_destruct<T> {
1919
_data: int,
2020
}
2121

22+
#[unsafe_destructor]
2223
impl<T:Const> Drop for arc_destruct<T> {
2324
fn finalize(&self) {}
2425
}

0 commit comments

Comments
 (0)