Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
1cc938a6
R
Rust
项目概览
int
/
Rust
11 个月 前同步成功
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
Rust
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
1cc938a6
编写于
10月 27, 2014
作者:
A
Alex Crichton
浏览文件
操作
浏览文件
下载
差异文件
rollup merge of #18337 : bkoropoff/unboxed-imm-upvar-fixes
上级
175d6a74
5662bbad
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
174 addition
and
76 deletion
+174
-76
src/librustc/middle/borrowck/check_loans.rs
src/librustc/middle/borrowck/check_loans.rs
+31
-8
src/librustc/middle/borrowck/mod.rs
src/librustc/middle/borrowck/mod.rs
+15
-6
src/librustc/middle/mem_categorization.rs
src/librustc/middle/mem_categorization.rs
+69
-62
src/test/compile-fail/unboxed-closure-immutable-capture.rs
src/test/compile-fail/unboxed-closure-immutable-capture.rs
+31
-0
src/test/run-pass/unboxed-closures-move-mutable.rs
src/test/run-pass/unboxed-closures-move-mutable.rs
+28
-0
未找到文件。
src/librustc/middle/borrowck/check_loans.rs
浏览文件 @
1cc938a6
...
...
@@ -777,13 +777,28 @@ fn check_assignment(&self,
// Otherwise, just a plain error.
match
assignee_cmt
.note
{
mc
::
NoteClosureEnv
(
upvar_id
)
=>
{
self
.bccx
.span_err
(
assignment_span
,
format!
(
"cannot assign to {}"
,
self
.bccx
.cmt_to_string
(
&*
assignee_cmt
))
.as_slice
());
self
.bccx
.span_note
(
self
.tcx
()
.map
.span
(
upvar_id
.closure_expr_id
),
"consider changing this closure to take self by mutable reference"
);
// If this is an `Fn` closure, it simply can't mutate upvars.
// If it's an `FnMut` closure, the original variable was declared immutable.
// We need to determine which is the case here.
let
kind
=
match
assignee_cmt
.upvar
()
.unwrap
()
.cat
{
mc
::
cat_upvar
(
mc
::
Upvar
{
kind
,
..
})
=>
kind
,
_
=>
unreachable!
()
};
if
kind
==
ty
::
FnUnboxedClosureKind
{
self
.bccx
.span_err
(
assignment_span
,
format!
(
"cannot assign to {}"
,
self
.bccx
.cmt_to_string
(
&*
assignee_cmt
))
.as_slice
());
self
.bccx
.span_note
(
self
.tcx
()
.map
.span
(
upvar_id
.closure_expr_id
),
"consider changing this closure to take self by mutable reference"
);
}
else
{
self
.bccx
.span_err
(
assignment_span
,
format!
(
"cannot assign to {} {}"
,
assignee_cmt
.mutbl
.to_user_str
(),
self
.bccx
.cmt_to_string
(
&*
assignee_cmt
))
.as_slice
());
}
}
_
=>
match
opt_loan_path
(
&
assignee_cmt
)
{
Some
(
lp
)
=>
{
...
...
@@ -825,12 +840,20 @@ fn mark_variable_as_used_mut(this: &CheckLoanCtxt,
mc
::
cat_rvalue
(
..
)
|
mc
::
cat_static_item
|
mc
::
cat_deref
(
_
,
_
,
mc
::
UnsafePtr
(
..
))
|
mc
::
cat_deref
(
_
,
_
,
mc
::
BorrowedPtr
(
..
))
|
mc
::
cat_deref
(
_
,
_
,
mc
::
Implicit
(
..
))
=>
{
assert_eq!
(
cmt
.mutbl
,
mc
::
McDeclared
);
return
;
}
mc
::
cat_deref
(
_
,
_
,
mc
::
BorrowedPtr
(
..
))
=>
{
assert_eq!
(
cmt
.mutbl
,
mc
::
McDeclared
);
// We need to drill down to upvar if applicable
match
cmt
.upvar
()
{
Some
(
b
)
=>
cmt
=
b
,
None
=>
return
}
}
mc
::
cat_deref
(
b
,
_
,
mc
::
OwnedPtr
)
=>
{
assert_eq!
(
cmt
.mutbl
,
mc
::
McInherited
);
cmt
=
b
;
...
...
src/librustc/middle/borrowck/mod.rs
浏览文件 @
1cc938a6
...
...
@@ -625,7 +625,7 @@ pub fn bckerr_to_string(&self, err: &BckError) -> String {
match
err
.code
{
err_mutbl
=>
{
let
descr
=
match
err
.cmt.note
{
mc
::
NoteClosureEnv
(
_
)
=>
{
mc
::
NoteClosureEnv
(
_
)
|
mc
::
NoteUpvarRef
(
_
)
=>
{
self
.cmt_to_string
(
&*
err
.cmt
)
}
_
=>
match
opt_loan_path
(
&
err
.cmt
)
{
...
...
@@ -761,11 +761,20 @@ pub fn note_and_explain_bckerr(&self, err: BckError) {
match
code
{
err_mutbl
(
..
)
=>
{
match
err
.cmt.note
{
mc
::
NoteClosureEnv
(
upvar_id
)
=>
{
self
.tcx.sess
.span_note
(
self
.tcx.map
.span
(
upvar_id
.closure_expr_id
),
"consider changing this closure to take
\
self by mutable reference"
);
mc
::
NoteClosureEnv
(
upvar_id
)
|
mc
::
NoteUpvarRef
(
upvar_id
)
=>
{
// If this is an `Fn` closure, it simply can't mutate upvars.
// If it's an `FnMut` closure, the original variable was declared immutable.
// We need to determine which is the case here.
let
kind
=
match
err
.cmt
.upvar
()
.unwrap
()
.cat
{
mc
::
cat_upvar
(
mc
::
Upvar
{
kind
,
..
})
=>
kind
,
_
=>
unreachable!
()
};
if
kind
==
ty
::
FnUnboxedClosureKind
{
self
.tcx.sess
.span_note
(
self
.tcx.map
.span
(
upvar_id
.closure_expr_id
),
"consider changing this closure to take
\
self by mutable reference"
);
}
}
_
=>
{}
}
...
...
src/librustc/middle/mem_categorization.rs
浏览文件 @
1cc938a6
...
...
@@ -655,51 +655,54 @@ fn cat_upvar(&self,
// FnOnce | copied | upvar -> &'up bk
// old stack | N/A | upvar -> &'env mut -> &'up bk
// old proc/once | copied | N/A
let
var_ty
=
if_ok!
(
self
.node_ty
(
var_id
));
let
upvar_id
=
ty
::
UpvarId
{
var_id
:
var_id
,
closure_expr_id
:
fn_node_id
};
// Do we need to deref through an env reference?
let
has_env_deref
=
kind
!=
ty
::
FnOnceUnboxedClosureKind
;
// Mutability of original variable itself
let
var_mutbl
=
MutabilityCategory
::
from_local
(
self
.tcx
(),
var_id
);
// Mutability of environment dereference
let
env_mutbl
=
match
kind
{
ty
::
FnOnceUnboxedClosureKind
=>
var_mutbl
,
ty
::
FnMutUnboxedClosureKind
=>
McInherited
,
ty
::
FnUnboxedClosureKind
=>
McImmutable
// Construct information about env pointer dereference, if any
let
mutbl
=
match
kind
{
ty
::
FnOnceUnboxedClosureKind
=>
None
,
// None, env is by-value
ty
::
FnMutUnboxedClosureKind
=>
match
mode
{
// Depends on capture type
ast
::
CaptureByValue
=>
Some
(
var_mutbl
),
// Mutable if the original var is
ast
::
CaptureByRef
=>
Some
(
McDeclared
)
// Mutable regardless
},
ty
::
FnUnboxedClosureKind
=>
Some
(
McImmutable
)
// Never mutable
};
let
env_info
=
mutbl
.map
(|
env_mutbl
|
{
// Look up the node ID of the closure body so we can construct
// a free region within it
let
fn_body_id
=
{
let
fn_expr
=
match
self
.tcx
()
.map
.find
(
fn_node_id
)
{
Some
(
ast_map
::
NodeExpr
(
e
))
=>
e
,
_
=>
unreachable!
()
};
// Look up the node ID of the closure body so we can construct
// a free region within it
let
fn_body_id
=
{
let
fn_expr
=
match
self
.tcx
()
.map
.find
(
fn_node_id
)
{
Some
(
ast_map
::
NodeExpr
(
e
))
=>
e
,
_
=>
unreachable!
()
match
fn_expr
.node
{
ast
::
ExprFnBlock
(
_
,
_
,
ref
body
)
|
ast
::
ExprProc
(
_
,
ref
body
)
|
ast
::
ExprUnboxedFn
(
_
,
_
,
_
,
ref
body
)
=>
body
.id
,
_
=>
unreachable!
()
}
};
match
fn_expr
.node
{
ast
::
ExprFnBlock
(
_
,
_
,
ref
body
)
|
ast
::
ExprProc
(
_
,
ref
body
)
|
ast
::
ExprUnboxedFn
(
_
,
_
,
_
,
ref
body
)
=>
body
.id
,
_
=>
unreachable!
()
}
};
// Region of environment pointer
let
env_region
=
ty
::
ReFree
(
ty
::
FreeRegion
{
scope_id
:
fn_body_id
,
bound_region
:
ty
::
BrEnv
});
// Region of environment pointer
let
env_region
=
ty
::
ReFree
(
ty
::
FreeRegion
{
scope_id
:
fn_body_id
,
bound_region
:
ty
::
BrEnv
});
let
env_ptr
=
BorrowedPtr
(
if
env_mutbl
.is_mutable
()
{
ty
::
MutBorrow
}
else
{
ty
::
ImmBorrow
},
env_region
);
let
env_ptr
=
BorrowedPtr
(
if
env_mutbl
.is_mutable
()
{
ty
::
MutBorrow
}
else
{
ty
::
ImmBorrow
},
env_region
);
let
var_ty
=
if_ok!
(
self
.node_ty
(
var_id
));
(
env_mutbl
,
env_ptr
)
});
// First, switch by capture mode
Ok
(
match
mode
{
...
...
@@ -717,25 +720,27 @@ fn cat_upvar(&self,
note
:
NoteNone
};
if
has_env_deref
{
// We need to add the env deref. This means that
// the above is actually immutable and has a ref
// type. However, nothing should actually look at
// the type, so we can get away with stuffing a
// `ty_err` in there instead of bothering to
// construct a proper one.
base
.mutbl
=
McImmutable
;
base
.ty
=
ty
::
mk_err
();
Rc
::
new
(
cmt_
{
id
:
id
,
span
:
span
,
cat
:
cat_deref
(
Rc
::
new
(
base
),
0
,
env_ptr
),
mutbl
:
env_mutbl
,
ty
:
var_ty
,
note
:
NoteClosureEnv
(
upvar_id
)
})
}
else
{
Rc
::
new
(
base
)
match
env_info
{
Some
((
env_mutbl
,
env_ptr
))
=>
{
// We need to add the env deref. This means
// that the above is actually immutable and
// has a ref type. However, nothing should
// actually look at the type, so we can get
// away with stuffing a `ty_err` in there
// instead of bothering to construct a proper
// one.
base
.mutbl
=
McImmutable
;
base
.ty
=
ty
::
mk_err
();
Rc
::
new
(
cmt_
{
id
:
id
,
span
:
span
,
cat
:
cat_deref
(
Rc
::
new
(
base
),
0
,
env_ptr
),
mutbl
:
env_mutbl
,
ty
:
var_ty
,
note
:
NoteClosureEnv
(
upvar_id
)
})
}
None
=>
Rc
::
new
(
base
)
}
},
ast
::
CaptureByRef
=>
{
...
...
@@ -755,16 +760,18 @@ fn cat_upvar(&self,
note
:
NoteNone
};
// As in the by-value case, add env deref if needed
if
has_env_deref
{
base
=
cmt_
{
id
:
id
,
span
:
span
,
cat
:
cat_deref
(
Rc
::
new
(
base
),
0
,
env_ptr
),
mutbl
:
env_mutbl
,
ty
:
ty
::
mk_err
(),
note
:
NoteClosureEnv
(
upvar_id
)
};
match
env_info
{
Some
((
env_mutbl
,
env_ptr
))
=>
{
base
=
cmt_
{
id
:
id
,
span
:
span
,
cat
:
cat_deref
(
Rc
::
new
(
base
),
0
,
env_ptr
),
mutbl
:
env_mutbl
,
ty
:
ty
::
mk_err
(),
note
:
NoteClosureEnv
(
upvar_id
)
};
}
None
=>
{}
}
// Look up upvar borrow so we can get its region
...
...
src/test/compile-fail/unboxed-closure-immutable-capture.rs
0 → 100644
浏览文件 @
1cc938a6
// Copyright 2014 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(unboxed_closures)]
// Test that even unboxed closures that are capable of mutating their
// environment cannot mutate captured variables that have not been
// declared mutable (#18335)
fn
set
(
x
:
&
mut
uint
)
{
*
x
=
0
;
}
fn
main
()
{
let
x
=
0u
;
move
|
&
mut
:|
x
=
1
;
//~ ERROR cannot assign
move
|
&
mut
:|
set
(
&
mut
x
);
//~ ERROR cannot borrow
move
|:|
x
=
1
;
//~ ERROR cannot assign
move
|:|
set
(
&
mut
x
);
//~ ERROR cannot borrow
|
&
mut
:|
x
=
1
;
//~ ERROR cannot assign
// FIXME: this should be `cannot borrow` (issue #18330)
|
&
mut
:|
set
(
&
mut
x
);
//~ ERROR cannot assign
|:|
x
=
1
;
//~ ERROR cannot assign
// FIXME: this should be `cannot borrow` (issue #18330)
|:|
set
(
&
mut
x
);
//~ ERROR cannot assign
}
src/test/run-pass/unboxed-closures-move-mutable.rs
0 → 100644
浏览文件 @
1cc938a6
// Copyright 2014 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(unboxed_closures)]
#![deny(unused_mut)]
// Test that mutating a mutable upvar in a capture-by-value unboxed
// closure does not ice (issue #18238) and marks the upvar as used
// mutably so we do not get a spurious warning about it not needing to
// be declared mutable (issue #18336).
fn
main
()
{
{
let
mut
x
=
0u
;
move
|
&
mut
:|
x
+=
1
;
}
{
let
mut
x
=
0u
;
move
|:|
x
+=
1
;
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录