Skip to content

Commit e478ced

Browse files
committed
auto merge of #6385 : huonw/rust/rustc-dtor-struct-match, r=nikomatsakis
**Caveat**: With the current commit, this check only works for `match`s, the checks (incorrectly) do not run for patterns in `let`s, and invalid/unsafe code compiles. I don't know how to fix this, I experimented with some things to try to make let patterns and match patterns run on the same code (since this would presumably fix many of the other unsoundness issues of let-patterns, e.g. #6225), but I don't understand enough of the code. (I think I heard someone talking about a fix for `let` being in progress?) Fixes #6344 and #6341.
2 parents 96de2b0 + 912a352 commit e478ced

7 files changed

+132
-23
lines changed

src/librustc/middle/check_match.rs

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -822,43 +822,65 @@ pub fn check_legality_of_move_bindings(cx: @MatchCheckCtxt,
822822
}
823823
}
824824
825-
// Now check to ensure that any move binding is not behind an @ or &.
826-
// This is always illegal.
825+
// Now check to ensure that any move binding is not behind an
826+
// @ or &, or within a struct with a destructor. This is
827+
// always illegal.
827828
let vt = visit::mk_vt(@visit::Visitor {
828-
visit_pat: |pat, behind_bad_pointer: bool, v| {
829+
visit_pat: |pat, (behind_bad_pointer, behind_dtor_struct): (bool, bool), v| {
829830
match pat.node {
830831
pat_ident(_, _, sub) => {
831832
debug!("(check legality of move) checking pat \
832-
ident with behind_bad_pointer %?",
833-
behind_bad_pointer);
833+
ident with behind_bad_pointer %? and behind_dtor_struct %?",
834+
behind_bad_pointer, behind_dtor_struct);
834835
835-
if behind_bad_pointer &&
836+
if behind_bad_pointer || behind_dtor_struct &&
836837
cx.moves_map.contains(&pat.id)
837838
{
838-
cx.tcx.sess.span_err(
839-
pat.span,
840-
"by-move pattern \
841-
bindings may not occur \
842-
behind @ or & bindings");
839+
let msg = if behind_bad_pointer {
840+
"by-move pattern bindings may not occur behind @ or & bindings"
841+
} else {
842+
"cannot bind by-move within struct (it has a destructor)"
843+
};
844+
cx.tcx.sess.span_err(pat.span, msg);
843845
}
844846
845847
match sub {
846848
None => {}
847849
Some(subpat) => {
848-
(v.visit_pat)(subpat, behind_bad_pointer, v);
850+
(v.visit_pat)(subpat,
851+
(behind_bad_pointer, behind_dtor_struct),
852+
v);
849853
}
850854
}
851855
}
852856
853857
pat_box(subpat) | pat_region(subpat) => {
854-
(v.visit_pat)(subpat, true, v);
858+
(v.visit_pat)(subpat, (true, behind_dtor_struct), v);
855859
}
856860
857-
_ => visit::visit_pat(pat, behind_bad_pointer, v)
861+
pat_struct(_, ref fields, _) => {
862+
let behind_dtor_struct = behind_dtor_struct ||
863+
(match cx.tcx.def_map.find(&pat.id) {
864+
Some(&def_struct(id)) => {
865+
ty::has_dtor(cx.tcx, id)
866+
}
867+
_ => false
868+
});
869+
debug!("(check legality of move) checking pat \
870+
struct with behind_bad_pointer %? and behind_dtor_struct %?",
871+
behind_bad_pointer, behind_dtor_struct);
872+
873+
for fields.each |fld| {
874+
(v.visit_pat)(fld.pat, (behind_bad_pointer,
875+
behind_dtor_struct), v)
876+
}
877+
}
878+
879+
_ => visit::visit_pat(pat, (behind_bad_pointer, behind_dtor_struct), v)
858880
}
859881
},
860-
.. *visit::default_visitor::<bool>()
882+
.. *visit::default_visitor::<(bool, bool)>()
861883
});
862-
(vt.visit_pat)(*pat, false, vt);
884+
(vt.visit_pat)(*pat, (false, false), vt);
863885
}
864886
}

src/librustc/middle/typeck/check/_match.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -340,12 +340,6 @@ pub fn check_struct_pat(pcx: &pat_ctxt, pat_id: ast::node_id, span: span,
340340
}
341341
}
342342

343-
// Forbid pattern-matching structs with destructors.
344-
if ty::has_dtor(tcx, class_id) {
345-
tcx.sess.span_err(span, "deconstructing struct not allowed in pattern \
346-
(it has a destructor)");
347-
}
348-
349343
check_struct_pat_fields(pcx, span, path, fields, class_fields, class_id,
350344
substitutions, etc);
351345
}

src/test/compile-fail/disallowed-deconstructing-destructing-struct.rs renamed to src/test/compile-fail/disallowed-deconstructing-destructing-struct-let.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// xfail-test #3024
12
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
23
// file at the top-level directory of this distribution and at
34
// http://rust-lang.org/COPYRIGHT.
@@ -19,7 +20,7 @@ impl Drop for X {
1920
}
2021

2122
fn unwrap(x: X) -> ~str {
22-
let X { x: y } = x; //~ ERROR deconstructing struct not allowed in pattern
23+
let X { x: y } = x; //~ ERROR cannot bind by-move within struct
2324
y
2425
}
2526

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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+
struct X {
12+
x: ~str,
13+
}
14+
15+
impl Drop for X {
16+
fn finalize(&self) {
17+
error!("value: %s", self.x);
18+
}
19+
}
20+
21+
fn main() {
22+
let x = X { x: ~"hello" };
23+
24+
match x {
25+
X { x: y } => error!("contents: %s", y)
26+
//~^ ERROR cannot bind by-move within struct
27+
}
28+
}

src/test/run-pass/issue-6341.rs

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+
#[deriving(Eq)]
12+
struct A { x: uint }
13+
14+
impl Drop for A {
15+
fn finalize(&self) {}
16+
}
17+
18+
fn main() {}

src/test/run-pass/issue-6344-let.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// xfail-test #3874
2+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
3+
// file at the top-level directory of this distribution and at
4+
// http://rust-lang.org/COPYRIGHT.
5+
//
6+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
7+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
8+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
9+
// option. This file may not be copied, modified, or distributed
10+
// except according to those terms.
11+
struct A { x: uint }
12+
13+
impl Drop for A {
14+
fn finalize(&self) {}
15+
}
16+
17+
fn main() {
18+
let a = A { x: 0 };
19+
20+
let A { x: ref x } = a;
21+
debug!("%?", x)
22+
}

src/test/run-pass/issue-6344-match.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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+
struct A { x: uint }
11+
12+
impl Drop for A {
13+
fn finalize(&self) {}
14+
}
15+
16+
fn main() {
17+
let a = A { x: 0 };
18+
19+
match a {
20+
A { x : ref x } => {
21+
debug!("%?", x)
22+
}
23+
}
24+
}

0 commit comments

Comments
 (0)