mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-24 07:44:10 +00:00
Prevent copies of resources into various things
This commit is contained in:
parent
9ba86178ef
commit
459353e107
@ -142,6 +142,52 @@ fn need_shared_lhs_rhs(tcx: ty::ctxt, a: @ast::expr, b: @ast::expr, op: str) {
|
||||
need_expr_kind(tcx, b, ast::kind_shared, op + " rhs");
|
||||
}
|
||||
|
||||
/*
|
||||
This ... is a hack (I find myself writing that too often *sadface*).
|
||||
|
||||
We need to be able to put pinned kinds into other types but such operations
|
||||
are conceptually copies, and pinned kinds can't do that, e.g.
|
||||
|
||||
let a = my_resource(x);
|
||||
let b = @a; // no-go
|
||||
|
||||
So this function attempts to make a loophole where resources can be put into
|
||||
other types as long as it's done in a safe way, specifically like
|
||||
|
||||
let b = @my_resource(x);
|
||||
*/
|
||||
fn need_shared_or_pinned_ctor(tcx: ty::ctxt, a: @ast::expr, descr: str) {
|
||||
let tk = type_and_kind(tcx, a);
|
||||
if tk.kind == ast::kind_pinned && !pinned_ctor(a) {
|
||||
let err =
|
||||
#fmt["mismatched kinds for %s: cannot copy pinned type %s",
|
||||
descr, util::ppaux::ty_to_str(tcx, tk.ty)];
|
||||
tcx.sess.span_err(a.span, err);
|
||||
let note =
|
||||
#fmt["try constructing %s directly into %s",
|
||||
util::ppaux::ty_to_str(tcx, tk.ty), descr];
|
||||
tcx.sess.span_note(a.span, note);
|
||||
} else if tk.kind != ast::kind_pinned {
|
||||
need_expr_kind(tcx, a, ast::kind_shared, descr);
|
||||
}
|
||||
|
||||
fn pinned_ctor(a: @ast::expr) -> bool {
|
||||
// FIXME: Technically a lambda block is also a pinned ctor
|
||||
alt a.node {
|
||||
ast::expr_call(cexpr, _) {
|
||||
// Assuming that if it's a call that it's safe to move in, mostly
|
||||
// because I don't know offhand how to ensure that it's a call
|
||||
// specifically to a resource constructor
|
||||
true
|
||||
}
|
||||
ast::expr_rec(_, _) {
|
||||
true
|
||||
}
|
||||
_ { false }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr(tcx: ty::ctxt, e: @ast::expr) {
|
||||
alt e.node {
|
||||
|
||||
@ -189,6 +235,27 @@ fn check_expr(tcx: ty::ctxt, e: @ast::expr) {
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::expr_unary(op, a) {
|
||||
alt op {
|
||||
ast::box(_) {
|
||||
need_shared_or_pinned_ctor(tcx, a, "'@' operand");
|
||||
}
|
||||
ast::uniq(_) {
|
||||
need_shared_or_pinned_ctor(tcx, a, "'~' operand");
|
||||
}
|
||||
_ { /* fall through */ }
|
||||
}
|
||||
}
|
||||
ast::expr_rec(fields, _) {
|
||||
for field in fields {
|
||||
need_shared_or_pinned_ctor(tcx, field.node.expr, "record field");
|
||||
}
|
||||
}
|
||||
ast::expr_tup(exprs) {
|
||||
for expr in exprs {
|
||||
need_shared_or_pinned_ctor(tcx, expr, "tuple parameter");
|
||||
}
|
||||
}
|
||||
_ { }
|
||||
}
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ fn check_variants_of_ast(crate: ast::crate, codemap: codemap::codemap,
|
||||
check_variants_T(crate, codemap, filename, "ty", stolen.tys, pprust::ty_to_str, replace_ty_in_crate, cx);
|
||||
}
|
||||
|
||||
fn check_variants_T<T>(
|
||||
fn check_variants_T<@T>(
|
||||
crate: ast::crate,
|
||||
codemap: codemap::codemap,
|
||||
filename: str,
|
||||
|
@ -1,5 +1,4 @@
|
||||
// xfail-test
|
||||
// error-pattern:mismatched kinds
|
||||
// error-pattern:mismatched kinds for '@' operand
|
||||
resource r(i: @mutable int) {
|
||||
*i = *i + 1;
|
||||
}
|
||||
@ -9,7 +8,7 @@ fn main() {
|
||||
{
|
||||
let j <- r(i);
|
||||
// No no no no no
|
||||
let k = @j;
|
||||
let k <- @j;
|
||||
}
|
||||
log_err *i;
|
||||
assert *i == 2;
|
||||
|
@ -1,5 +1,4 @@
|
||||
// xfail-test
|
||||
// error-pattern:mismatched kinds
|
||||
// error-pattern:mismatched kinds for record field
|
||||
resource r(i: @mutable int) {
|
||||
*i = *i + 1;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// xfail-test
|
||||
// error-pattern:mismatched kinds
|
||||
// error-pattern:mismatched kinds for tag parameter
|
||||
resource r(i: @mutable int) {
|
||||
*i = *i + 1;
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
// xfail-test
|
||||
// error-pattern:mismatched kinds
|
||||
// error-pattern:mismatched kinds for tuple parameter
|
||||
resource r(i: @mutable int) {
|
||||
*i = *i + 1;
|
||||
}
|
||||
|
15
src/test/compile-fail/copy-res-into-unique.rs
Normal file
15
src/test/compile-fail/copy-res-into-unique.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// error-pattern:mismatched kinds for '~' operand
|
||||
resource r(i: @mutable int) {
|
||||
*i = *i + 1;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let i = @mutable 0;
|
||||
{
|
||||
let j <- r(i);
|
||||
// No no no no no
|
||||
let k <- ~j;
|
||||
}
|
||||
log_err *i;
|
||||
assert *i == 2;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
|
||||
|
||||
obj ob<K>(k: K) {
|
||||
obj ob<@K>(k: K) {
|
||||
iter foo() -> @{a: K} { put @{a: k}; }
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
obj ob<K>(k: K) {
|
||||
obj ob<@K>(k: K) {
|
||||
iter foo() -> ~{a: K} { put ~{a: k}; }
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
|
||||
|
||||
fn box<T>(x: {x: T, y: T, z: T}) -> @{x: T, y: T, z: T} { ret @x; }
|
||||
fn box<@T>(x: {x: T, y: T, z: T}) -> @{x: T, y: T, z: T} { ret @x; }
|
||||
|
||||
fn main() {
|
||||
let x: @{x: int, y: int, z: int} = box::<int>({x: 1, y: 2, z: 3});
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
type recbox<T> = {x: @T};
|
||||
|
||||
fn reclift<T>(t: T) -> recbox<T> { ret {x: @t}; }
|
||||
fn reclift<@T>(t: T) -> recbox<T> { ret {x: @t}; }
|
||||
|
||||
fn main() {
|
||||
let foo: int = 17;
|
||||
|
70
src/test/run-pass/init-res-into-things.rs
Normal file
70
src/test/run-pass/init-res-into-things.rs
Normal file
@ -0,0 +1,70 @@
|
||||
// Resources can't be copied into other types but still need to be able
|
||||
// to find their way into things.
|
||||
|
||||
resource r(i: @mutable int) {
|
||||
*i = *i + 1;
|
||||
}
|
||||
|
||||
fn test_box() {
|
||||
let i = @mutable 0;
|
||||
{
|
||||
let a <- @r(i);
|
||||
}
|
||||
assert *i == 1;
|
||||
}
|
||||
|
||||
fn test_rec() {
|
||||
let i = @mutable 0;
|
||||
{
|
||||
let a <- {x: r(i)};
|
||||
}
|
||||
assert *i == 1;
|
||||
}
|
||||
|
||||
fn test_tag() {
|
||||
tag t {
|
||||
t0(r);
|
||||
}
|
||||
|
||||
let i = @mutable 0;
|
||||
{
|
||||
let a <- t0(r(i));
|
||||
}
|
||||
assert *i == 1;
|
||||
}
|
||||
|
||||
fn test_tup() {
|
||||
let i = @mutable 0;
|
||||
{
|
||||
let a <- (r(i), 0);
|
||||
}
|
||||
assert *i == 1;
|
||||
}
|
||||
|
||||
fn test_unique() {
|
||||
let i = @mutable 0;
|
||||
{
|
||||
let a <- ~r(i);
|
||||
}
|
||||
assert *i == 1;
|
||||
}
|
||||
|
||||
fn test_box_rec() {
|
||||
let i = @mutable 0;
|
||||
{
|
||||
let a <- @{
|
||||
x: r(i)
|
||||
};
|
||||
}
|
||||
assert *i == 1;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test_box();
|
||||
test_rec();
|
||||
// FIXME: tag constructors don't optimize their arguments into moves
|
||||
// test_tag();
|
||||
test_tup();
|
||||
test_unique();
|
||||
test_box_rec();
|
||||
}
|
Loading…
Reference in New Issue
Block a user