Skip to content

Commit f6743fe

Browse files
committed
librustc: allow destructuring of structs with destructors if the pattern has no moves.
This check only works for `match`s, the checks (incorrectly) do not run for patterns in `let`s.
1 parent ad8e236 commit f6743fe

File tree

5 files changed

+86
-23
lines changed

5 files changed

+86
-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
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() {}

0 commit comments

Comments
 (0)