From 1ffcc6fc82caae4e6d17f1156c815998a0b5e080 Mon Sep 17 00:00:00 2001 From: Ben Blum Date: Thu, 13 Jun 2013 20:57:23 -0400 Subject: [PATCH] Allow ~fn:Copy() to be copied. --- src/librustc/middle/ty.rs | 27 +++++++++++++----- ...losure-bounds-copyable-squiggle-closure.rs | 25 +++++++++++++++++ ...ds-squiggle-closure-as-copyable-typaram.rs | 28 +++++++++++++++++++ 3 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 src/test/run-pass/closure-bounds-copyable-squiggle-closure.rs create mode 100644 src/test/run-pass/closure-bounds-squiggle-closure-as-copyable-typaram.rs diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index b76f30a70410..90cd8a8665ea 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1856,7 +1856,7 @@ impl TypeContents { } pub fn noncopyable(_cx: ctxt) -> TypeContents { - TC_DTOR + TC_BORROWED_MUT + TC_ONCE_CLOSURE + TC_OWNED_CLOSURE + + TC_DTOR + TC_BORROWED_MUT + TC_ONCE_CLOSURE + TC_NONCOPY_TRAIT + TC_EMPTY_ENUM } @@ -1905,13 +1905,19 @@ impl TypeContents { } pub fn needs_drop(&self, cx: ctxt) -> bool { + if self.intersects(TC_NONCOPY_TRAIT) { + // Currently all noncopyable existentials are 2nd-class types + // behind owned pointers. With dynamically-sized types, remove + // this assertion. + assert!(self.intersects(TC_OWNED_POINTER)); + } let tc = TC_MANAGED + TC_DTOR + TypeContents::owned(cx); self.intersects(tc) } pub fn owned(_cx: ctxt) -> TypeContents { //! Any kind of owned contents. - TC_OWNED_CLOSURE + TC_OWNED_POINTER + TC_OWNED_VEC + TC_OWNED_POINTER + TC_OWNED_VEC } } @@ -1945,8 +1951,8 @@ static TC_OWNED_POINTER: TypeContents = TypeContents{bits: 0b0000_0000_0010}; /// Contains an owned vector ~[] or owned string ~str static TC_OWNED_VEC: TypeContents = TypeContents{bits: 0b0000_0000_0100}; -/// Contains a ~fn() or a ~Trait, which is non-copyable. -static TC_OWNED_CLOSURE: TypeContents = TypeContents{bits: 0b0000_0000_1000}; +/// Contains a non-copyable ~fn() or a ~Trait (NOT a ~fn:Copy() or ~Trait:Copy). +static TC_NONCOPY_TRAIT: TypeContents = TypeContents{bits: 0b0000_0000_1000}; /// Type with a destructor static TC_DTOR: TypeContents = TypeContents{bits: 0b0000_0001_0000}; @@ -2061,7 +2067,8 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { } ty_trait(_, _, UniqTraitStore, _, _bounds) => { - TC_OWNED_CLOSURE + // FIXME(#3569): Make this conditional on the trait's bounds. + TC_NONCOPY_TRAIT + TC_OWNED_POINTER } ty_trait(_, _, BoxTraitStore, mutbl, _bounds) => { @@ -2184,7 +2191,9 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { match sigil { ast::BorrowedSigil => TC_BORROWED_POINTER, ast::ManagedSigil => TC_MANAGED, - ast::OwnedSigil => TC_OWNED_CLOSURE + // FIXME(#3569): Looks like noncopyability should depend + // on the bounds, but I don't think this case ever comes up. + ast::OwnedSigil => TC_NONCOPY_TRAIT + TC_OWNED_POINTER, } } @@ -2258,7 +2267,11 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { let st = match cty.sigil { ast::BorrowedSigil => TC_BORROWED_POINTER, ast::ManagedSigil => TC_MANAGED, - ast::OwnedSigil => TC_OWNED_CLOSURE + ast::OwnedSigil => if cty.bounds.contains_elem(BoundCopy) { + TC_OWNED_POINTER + } else { + TC_OWNED_POINTER + TC_NONCOPY_TRAIT + } }; let rt = borrowed_contents(cty.region, m_imm); let ot = match cty.onceness { diff --git a/src/test/run-pass/closure-bounds-copyable-squiggle-closure.rs b/src/test/run-pass/closure-bounds-copyable-squiggle-closure.rs new file mode 100644 index 000000000000..f39c914916ff --- /dev/null +++ b/src/test/run-pass/closure-bounds-copyable-squiggle-closure.rs @@ -0,0 +1,25 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-pretty + +// Tests correct copying of heap closures' environments. + +fn foo(x: ~fn:Copy()) -> (~fn(), ~fn()) { + (copy x, x) +} +fn main() { + let v = ~[~[1,2,3],~[4,5,6]]; // shouldn't get double-freed + let (f1,f2) = do foo { + assert!(v.len() == 2); + }; + f1(); + f2(); +} diff --git a/src/test/run-pass/closure-bounds-squiggle-closure-as-copyable-typaram.rs b/src/test/run-pass/closure-bounds-squiggle-closure-as-copyable-typaram.rs new file mode 100644 index 000000000000..2fdce4e5c7cd --- /dev/null +++ b/src/test/run-pass/closure-bounds-squiggle-closure-as-copyable-typaram.rs @@ -0,0 +1,28 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-pretty + +// Tests correct copying of heap closures' environments. + +fn bar(x: T) -> (T, T) { + (copy x, x) +} +fn foo(x: ~fn:Copy()) -> (~fn(), ~fn()) { + bar(x) +} +fn main() { + let v = ~[~[1,2,3],~[4,5,6]]; // shouldn't get double-freed + let (f1,f2) = do foo { + assert!(v.len() == 2); + }; + f1(); + f2(); +}