Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
fc04eaac
R
Rust
项目概览
int
/
Rust
大约 1 年 前同步成功
通知
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,发现更多精彩内容 >>
提交
fc04eaac
编写于
2月 28, 2017
作者:
T
Taylor Cramer
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Implement ? in catch expressions and add tests
上级
703b2462
变更
16
隐藏空白更改
内联
并排
Showing
16 changed file
with
570 addition
and
272 deletion
+570
-272
src/librustc/cfg/construct.rs
src/librustc/cfg/construct.rs
+72
-22
src/librustc/hir/intravisit.rs
src/librustc/hir/intravisit.rs
+12
-6
src/librustc/hir/lowering.rs
src/librustc/hir/lowering.rs
+56
-33
src/librustc/hir/mod.rs
src/librustc/hir/mod.rs
+20
-1
src/librustc/middle/liveness.rs
src/librustc/middle/liveness.rs
+66
-69
src/librustc_mir/build/expr/into.rs
src/librustc_mir/build/expr/into.rs
+15
-3
src/librustc_mir/build/expr/stmt.rs
src/librustc_mir/build/expr/stmt.rs
+7
-5
src/librustc_mir/build/mod.rs
src/librustc_mir/build/mod.rs
+3
-3
src/librustc_mir/build/scope.rs
src/librustc_mir/build/scope.rs
+25
-24
src/librustc_mir/hair/cx/expr.rs
src/librustc_mir/hair/cx/expr.rs
+13
-10
src/librustc_passes/loops.rs
src/librustc_passes/loops.rs
+16
-9
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/mod.rs
+153
-87
src/test/compile-fail/catch-bad-lifetime.rs
src/test/compile-fail/catch-bad-lifetime.rs
+35
-0
src/test/compile-fail/catch-bad-type.rs
src/test/compile-fail/catch-bad-type.rs
+21
-0
src/test/compile-fail/catch-opt-init.rs
src/test/compile-fail/catch-opt-init.rs
+22
-0
src/test/run-pass/catch-expr.rs
src/test/run-pass/catch-expr.rs
+34
-0
未找到文件。
src/librustc/cfg/construct.rs
浏览文件 @
fc04eaac
...
...
@@ -22,13 +22,20 @@ struct CFGBuilder<'a, 'tcx: 'a> {
graph
:
CFGGraph
,
fn_exit
:
CFGIndex
,
loop_scopes
:
Vec
<
LoopScope
>
,
breakable_block_scopes
:
Vec
<
BlockScope
>
,
}
#[derive(Copy,
Clone)]
struct
BlockScope
{
block_expr_id
:
ast
::
NodeId
,
// id of breakable block expr node
break_index
:
CFGIndex
,
// where to go on `break`
}
#[derive(Copy,
Clone)]
struct
LoopScope
{
loop_id
:
ast
::
NodeId
,
// id of loop/while node
continue_index
:
CFGIndex
,
// where to go on a `loop`
break_index
:
CFGIndex
,
// where to go on a `break
break_index
:
CFGIndex
,
// where to go on a `break
`
}
pub
fn
construct
<
'a
,
'tcx
>
(
tcx
:
TyCtxt
<
'a
,
'tcx
,
'tcx
>
,
...
...
@@ -53,6 +60,7 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
graph
:
graph
,
fn_exit
:
fn_exit
,
loop_scopes
:
Vec
::
new
(),
breakable_block_scopes
:
Vec
::
new
(),
};
body_exit
=
cfg_builder
.expr
(
&
body
.value
,
entry
);
cfg_builder
.add_contained_edge
(
body_exit
,
fn_exit
);
...
...
@@ -66,14 +74,34 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl
<
'a
,
'tcx
>
CFGBuilder
<
'a
,
'tcx
>
{
fn
block
(
&
mut
self
,
blk
:
&
hir
::
Block
,
pred
:
CFGIndex
)
->
CFGIndex
{
let
mut
stmts_exit
=
pred
;
for
stmt
in
&
blk
.stmts
{
stmts_exit
=
self
.stmt
(
stmt
,
stmts_exit
);
}
if
let
Some
(
break_to_expr_id
)
=
blk
.break_to_expr_id
{
let
expr_exit
=
self
.add_ast_node
(
blk
.id
,
&
[]);
self
.breakable_block_scopes
.push
(
BlockScope
{
block_expr_id
:
break_to_expr_id
,
break_index
:
expr_exit
,
});
let
mut
stmts_exit
=
pred
;
for
stmt
in
&
blk
.stmts
{
stmts_exit
=
self
.stmt
(
stmt
,
stmts_exit
);
}
let
blk_expr_exit
=
self
.opt_expr
(
&
blk
.expr
,
stmts_exit
);
self
.add_contained_edge
(
blk_expr_exit
,
blk_expr_exit
);
self
.breakable_block_scopes
.pop
();
expr_exit
}
else
{
let
mut
stmts_exit
=
pred
;
for
stmt
in
&
blk
.stmts
{
stmts_exit
=
self
.stmt
(
stmt
,
stmts_exit
);
}
let
expr_exit
=
self
.opt_expr
(
&
blk
.expr
,
stmts_exit
);
let
expr_exit
=
self
.opt_expr
(
&
blk
.expr
,
stmts_exit
);
self
.add_ast_node
(
blk
.id
,
&
[
expr_exit
])
self
.add_ast_node
(
blk
.id
,
&
[
expr_exit
])
}
}
fn
stmt
(
&
mut
self
,
stmt
:
&
hir
::
Stmt
,
pred
:
CFGIndex
)
->
CFGIndex
{
...
...
@@ -295,18 +323,18 @@ fn expr(&mut self, expr: &hir::Expr, pred: CFGIndex) -> CFGIndex {
hir
::
ExprBreak
(
destination
,
ref
opt_expr
)
=>
{
let
v
=
self
.opt_expr
(
opt_expr
,
pred
);
let
loop_scope
=
self
.find_scope
(
expr
,
destination
);
let
(
scope_id
,
break_dest
)
=
self
.find_scope_edge
(
expr
,
destination
,
ScopeCfKind
::
Break
);
let
b
=
self
.add_ast_node
(
expr
.id
,
&
[
v
]);
self
.add_exiting_edge
(
expr
,
b
,
loop_scope
,
loop_scope
.break_index
);
self
.add_exiting_edge
(
expr
,
b
,
scope_id
,
break_dest
);
self
.add_unreachable_node
()
}
hir
::
ExprAgain
(
destination
)
=>
{
let
loop_scope
=
self
.find_scope
(
expr
,
destination
);
let
(
scope_id
,
cont_dest
)
=
self
.find_scope_edge
(
expr
,
destination
,
ScopeCfKind
::
Continue
);
let
a
=
self
.add_ast_node
(
expr
.id
,
&
[
pred
]);
self
.add_exiting_edge
(
expr
,
a
,
loop_scope
,
loop_scope
.continue_index
);
self
.add_exiting_edge
(
expr
,
a
,
scope_id
,
cont_dest
);
self
.add_unreachable_node
()
}
...
...
@@ -552,11 +580,11 @@ fn add_contained_edge(&mut self,
fn
add_exiting_edge
(
&
mut
self
,
from_expr
:
&
hir
::
Expr
,
from_index
:
CFGIndex
,
to_loop
:
LoopScope
,
scope_id
:
ast
::
NodeId
,
to_index
:
CFGIndex
)
{
let
mut
data
=
CFGEdgeData
{
exiting_scopes
:
vec!
[]
};
let
mut
scope
=
self
.tcx.region_maps
.node_extent
(
from_expr
.id
);
let
target_scope
=
self
.tcx.region_maps
.node_extent
(
to_loop
.loop
_id
);
let
target_scope
=
self
.tcx.region_maps
.node_extent
(
scope
_id
);
while
scope
!=
target_scope
{
data
.exiting_scopes
.push
(
scope
.node_id
(
&
self
.tcx.region_maps
));
scope
=
self
.tcx.region_maps
.encl_scope
(
scope
);
...
...
@@ -576,20 +604,42 @@ fn add_returning_edge(&mut self,
self
.graph
.add_edge
(
from_index
,
self
.fn_exit
,
data
);
}
fn
find_scope
(
&
self
,
fn
find_scope
_edge
(
&
self
,
expr
:
&
hir
::
Expr
,
destination
:
hir
::
Destination
)
->
LoopScope
{
match
destination
.loop_id
.into
()
{
Ok
(
loop_id
)
=>
{
destination
:
hir
::
Destination
,
scope_cf_kind
:
ScopeCfKind
)
->
(
ast
::
NodeId
,
CFGIndex
)
{
match
destination
.target_id
{
hir
::
ScopeTarget
::
Block
(
block_expr_id
)
=>
{
for
b
in
&
self
.breakable_block_scopes
{
if
b
.block_expr_id
==
block_expr_id
{
return
(
block_expr_id
,
match
scope_cf_kind
{
ScopeCfKind
::
Break
=>
b
.break_index
,
ScopeCfKind
::
Continue
=>
bug!
(
"can't continue to block"
),
});
}
}
span_bug!
(
expr
.span
,
"no block expr for id {}"
,
block_expr_id
);
}
hir
::
ScopeTarget
::
Loop
(
hir
::
LoopIdResult
::
Ok
(
loop_id
))
=>
{
for
l
in
&
self
.loop_scopes
{
if
l
.loop_id
==
loop_id
{
return
*
l
;
return
(
loop_id
,
match
scope_cf_kind
{
ScopeCfKind
::
Break
=>
l
.break_index
,
ScopeCfKind
::
Continue
=>
l
.continue_index
,
});
}
}
span_bug!
(
expr
.span
,
"no loop scope for id {}"
,
loop_id
);
}
Err
(
err
)
=>
span_bug!
(
expr
.span
,
"loop scope error: {}"
,
err
),
hir
::
ScopeTarget
::
Loop
(
hir
::
LoopIdResult
::
Err
(
err
))
=>
span_bug!
(
expr
.span
,
"loop scope error: {}"
,
err
),
}
}
}
#[derive(Copy,
Clone,
Eq,
PartialEq)]
enum
ScopeCfKind
{
Break
,
Continue
,
}
src/librustc/hir/intravisit.rs
浏览文件 @
fc04eaac
...
...
@@ -1008,18 +1008,24 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
}
ExprBreak
(
label
,
ref
opt_expr
)
=>
{
label
.ident
.map
(|
ident
|
{
if
let
Ok
(
loop_id
)
=
label
.loop_id
.into
()
{
visitor
.visit_def_mention
(
Def
::
Label
(
loop_id
));
}
match
label
.target_id
{
ScopeTarget
::
Block
(
node_id
)
|
ScopeTarget
::
Loop
(
LoopIdResult
::
Ok
(
node_id
))
=>
visitor
.visit_def_mention
(
Def
::
Label
(
node_id
)),
ScopeTarget
::
Loop
(
LoopIdResult
::
Err
(
_
))
=>
{},
};
visitor
.visit_name
(
ident
.span
,
ident
.node.name
);
});
walk_list!
(
visitor
,
visit_expr
,
opt_expr
);
}
ExprAgain
(
label
)
=>
{
label
.ident
.map
(|
ident
|
{
if
let
Ok
(
loop_id
)
=
label
.loop_id
.into
()
{
visitor
.visit_def_mention
(
Def
::
Label
(
loop_id
));
}
match
label
.target_id
{
ScopeTarget
::
Block
(
_
)
=>
bug!
(
"can't `continue` to a non-loop block"
),
ScopeTarget
::
Loop
(
LoopIdResult
::
Ok
(
node_id
))
=>
visitor
.visit_def_mention
(
Def
::
Label
(
node_id
)),
ScopeTarget
::
Loop
(
LoopIdResult
::
Err
(
_
))
=>
{},
};
visitor
.visit_name
(
ident
.span
,
ident
.node.name
);
});
}
...
...
src/librustc/hir/lowering.rs
浏览文件 @
fc04eaac
...
...
@@ -356,22 +356,26 @@ fn lower_opt_sp_ident(&mut self, o_id: Option<Spanned<Ident>>) -> Option<Spanned
o_id
.map
(|
sp_ident
|
respan
(
sp_ident
.span
,
sp_ident
.node.name
))
}
fn
lower_destination
(
&
mut
self
,
destination
:
Option
<
(
NodeId
,
Spanned
<
Ident
>
)
>
)
fn
lower_
loop_
destination
(
&
mut
self
,
destination
:
Option
<
(
NodeId
,
Spanned
<
Ident
>
)
>
)
->
hir
::
Destination
{
match
destination
{
Some
((
id
,
label_ident
))
=>
hir
::
Destination
{
ident
:
Some
(
label_ident
),
loop_id
:
if
let
Def
::
Label
(
loop_id
)
=
self
.expect_full_def
(
id
)
{
Some
((
id
,
label_ident
))
=>
{
let
target
=
if
let
Def
::
Label
(
loop_id
)
=
self
.expect_full_def
(
id
)
{
hir
::
LoopIdResult
::
Ok
(
loop_id
)
}
else
{
hir
::
LoopIdResult
::
Err
(
hir
::
LoopIdError
::
UnresolvedLabel
)
};
hir
::
Destination
{
ident
:
Some
(
label_ident
),
target_id
:
hir
::
ScopeTarget
::
Loop
(
target
),
}
},
None
=>
hir
::
Destination
{
ident
:
None
,
loop_id
:
self
.loop_scopes
.last
()
.map
(|
innermost_loop_id
|
Ok
(
*
innermost_loop_id
))
.unwrap_or
(
Err
(
hir
::
LoopIdError
::
OutsideLoopScope
))
.into
()
target_id
:
hir
::
ScopeTarget
::
Loop
(
self
.loop_scopes
.last
()
.map
(|
innermost_loop_id
|
Ok
(
*
innermost_loop_id
))
.unwrap_or
(
Err
(
hir
::
LoopIdError
::
OutsideLoopScope
))
.into
())
}
}
}
...
...
@@ -990,7 +994,7 @@ fn lower_bounds(&mut self, bounds: &[TyParamBound]) -> hir::TyParamBounds {
bounds
.iter
()
.map
(|
bound
|
self
.lower_ty_param_bound
(
bound
))
.collect
()
}
fn
lower_block
(
&
mut
self
,
b
:
&
Block
)
->
P
<
hir
::
Block
>
{
fn
lower_block
(
&
mut
self
,
b
:
&
Block
,
break_to
:
Option
<
NodeId
>
)
->
P
<
hir
::
Block
>
{
let
mut
expr
=
None
;
let
mut
stmts
=
b
.stmts
.iter
()
.flat_map
(|
s
|
self
.lower_stmt
(
s
))
.collect
::
<
Vec
<
_
>>
();
...
...
@@ -1008,6 +1012,7 @@ fn lower_block(&mut self, b: &Block) -> P<hir::Block> {
expr
:
expr
,
rules
:
self
.lower_block_check_mode
(
&
b
.rules
),
span
:
b
.span
,
break_to_expr_id
:
break_to
,
})
}
...
...
@@ -1085,7 +1090,7 @@ fn lower_item_kind(&mut self,
}
ItemKind
::
Fn
(
ref
decl
,
unsafety
,
constness
,
abi
,
ref
generics
,
ref
body
)
=>
{
self
.with_new_scopes
(|
this
|
{
let
body
=
this
.lower_block
(
body
);
let
body
=
this
.lower_block
(
body
,
None
);
let
body
=
this
.expr_block
(
body
,
ThinVec
::
new
());
let
body_id
=
this
.record_body
(
body
,
Some
(
decl
));
hir
::
ItemFn
(
this
.lower_fn_decl
(
decl
),
...
...
@@ -1179,7 +1184,7 @@ fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem {
hir
::
TraitMethod
::
Required
(
names
))
}
TraitItemKind
::
Method
(
ref
sig
,
Some
(
ref
body
))
=>
{
let
body
=
this
.lower_block
(
body
);
let
body
=
this
.lower_block
(
body
,
None
);
let
expr
=
this
.expr_block
(
body
,
ThinVec
::
new
());
let
body_id
=
this
.record_body
(
expr
,
Some
(
&
sig
.decl
));
hir
::
TraitItemKind
::
Method
(
this
.lower_method_sig
(
sig
),
...
...
@@ -1235,7 +1240,7 @@ fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem {
hir
::
ImplItemKind
::
Const
(
this
.lower_ty
(
ty
),
body_id
)
}
ImplItemKind
::
Method
(
ref
sig
,
ref
body
)
=>
{
let
body
=
this
.lower_block
(
body
);
let
body
=
this
.lower_block
(
body
,
None
);
let
expr
=
this
.expr_block
(
body
,
ThinVec
::
new
());
let
body_id
=
this
.record_body
(
expr
,
Some
(
&
sig
.decl
));
hir
::
ImplItemKind
::
Method
(
this
.lower_method_sig
(
sig
),
body_id
)
...
...
@@ -1662,6 +1667,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
id
:
id
,
rules
:
hir
::
DefaultBlock
,
span
:
span
,
break_to_expr_id
:
None
,
});
P
(
self
.expr_block
(
blk
,
ThinVec
::
new
()))
}
...
...
@@ -1669,24 +1675,24 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
}
});
hir
::
ExprIf
(
P
(
self
.lower_expr
(
cond
)),
self
.lower_block
(
blk
),
else_opt
)
hir
::
ExprIf
(
P
(
self
.lower_expr
(
cond
)),
self
.lower_block
(
blk
,
None
),
else_opt
)
}
ExprKind
::
While
(
ref
cond
,
ref
body
,
opt_ident
)
=>
{
self
.with_loop_scope
(
e
.id
,
|
this
|
hir
::
ExprWhile
(
this
.with_loop_condition_scope
(|
this
|
P
(
this
.lower_expr
(
cond
))),
this
.lower_block
(
body
),
this
.lower_block
(
body
,
None
),
this
.lower_opt_sp_ident
(
opt_ident
)))
}
ExprKind
::
Loop
(
ref
body
,
opt_ident
)
=>
{
self
.with_loop_scope
(
e
.id
,
|
this
|
hir
::
ExprLoop
(
this
.lower_block
(
body
),
hir
::
ExprLoop
(
this
.lower_block
(
body
,
None
),
this
.lower_opt_sp_ident
(
opt_ident
),
hir
::
LoopSource
::
Loop
))
}
ExprKind
::
Catch
(
ref
body
)
=>
{
// FIXME(cramertj): Add catch to HIR
self
.with_catch_scope
(
e
.id
,
|
this
|
hir
::
ExprBlock
(
this
.lower_block
(
body
)))
self
.with_catch_scope
(
e
.id
,
|
this
|
hir
::
ExprBlock
(
this
.lower_block
(
body
,
Some
(
e
.id
)
)))
}
ExprKind
::
Match
(
ref
expr
,
ref
arms
)
=>
{
hir
::
ExprMatch
(
P
(
self
.lower_expr
(
expr
)),
...
...
@@ -1704,7 +1710,7 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
})
})
}
ExprKind
::
Block
(
ref
blk
)
=>
hir
::
ExprBlock
(
self
.lower_block
(
blk
)),
ExprKind
::
Block
(
ref
blk
)
=>
hir
::
ExprBlock
(
self
.lower_block
(
blk
,
None
)),
ExprKind
::
Assign
(
ref
el
,
ref
er
)
=>
{
hir
::
ExprAssign
(
P
(
self
.lower_expr
(
el
)),
P
(
self
.lower_expr
(
er
)))
}
...
...
@@ -1783,10 +1789,11 @@ fn make_struct(this: &mut LoweringContext,
let
label_result
=
if
self
.is_in_loop_condition
&&
opt_ident
.is_none
()
{
hir
::
Destination
{
ident
:
opt_ident
,
loop_id
:
Err
(
hir
::
LoopIdError
::
UnlabeledCfInWhileCondition
)
.into
(),
target_id
:
hir
::
ScopeTarget
::
Loop
(
Err
(
hir
::
LoopIdError
::
UnlabeledCfInWhileCondition
)
.into
()),
}
}
else
{
self
.lower_destination
(
opt_ident
.map
(|
ident
|
(
e
.id
,
ident
)))
self
.lower_
loop_
destination
(
opt_ident
.map
(|
ident
|
(
e
.id
,
ident
)))
};
hir
::
ExprBreak
(
label_result
,
...
...
@@ -1797,11 +1804,11 @@ fn make_struct(this: &mut LoweringContext,
if
self
.is_in_loop_condition
&&
opt_ident
.is_none
()
{
hir
::
Destination
{
ident
:
opt_ident
,
loop_id
:
Err
(
hir
::
LoopIdError
::
UnlabeledCfInWhileCondition
)
.into
(),
target_id
:
hir
::
ScopeTarget
::
Loop
(
Err
(
hir
::
LoopIdError
::
UnlabeledCfInWhileCondition
)
.into
()
)
,
}
}
else
{
self
.lower_destination
(
opt_ident
.map
(
|
ident
|
(
e
.id
,
ident
)))
self
.lower_
loop_
destination
(
opt_ident
.map
(
|
ident
|
(
e
.id
,
ident
)))
}),
ExprKind
::
Ret
(
ref
e
)
=>
hir
::
ExprRet
(
e
.as_ref
()
.map
(|
x
|
P
(
self
.lower_expr
(
x
)))),
ExprKind
::
InlineAsm
(
ref
asm
)
=>
{
...
...
@@ -1859,7 +1866,7 @@ fn make_struct(this: &mut LoweringContext,
// `<pat> => <body>`
let
pat_arm
=
{
let
body
=
self
.lower_block
(
body
);
let
body
=
self
.lower_block
(
body
,
None
);
let
body_expr
=
P
(
self
.expr_block
(
body
,
ThinVec
::
new
()));
let
pat
=
self
.lower_pat
(
pat
);
self
.arm
(
hir_vec!
[
pat
],
body_expr
)
...
...
@@ -1946,7 +1953,7 @@ fn make_struct(this: &mut LoweringContext,
// Note that the block AND the condition are evaluated in the loop scope.
// This is done to allow `break` from inside the condition of the loop.
let
(
body
,
break_expr
,
sub_expr
)
=
self
.with_loop_scope
(
e
.id
,
|
this
|
(
this
.lower_block
(
body
),
this
.lower_block
(
body
,
None
),
this
.expr_break
(
e
.span
,
ThinVec
::
new
()),
this
.with_loop_condition_scope
(|
this
|
P
(
this
.lower_expr
(
sub_expr
))),
));
...
...
@@ -2007,7 +2014,8 @@ fn make_struct(this: &mut LoweringContext,
// `::std::option::Option::Some(<pat>) => <body>`
let
pat_arm
=
{
let
body_block
=
self
.with_loop_scope
(
e
.id
,
|
this
|
this
.lower_block
(
body
));
let
body_block
=
self
.with_loop_scope
(
e
.id
,
|
this
|
this
.lower_block
(
body
,
None
));
let
body_expr
=
P
(
self
.expr_block
(
body_block
,
ThinVec
::
new
()));
let
pat
=
self
.lower_pat
(
pat
);
let
some_pat
=
self
.pat_some
(
e
.span
,
pat
);
...
...
@@ -2090,14 +2098,12 @@ fn make_struct(this: &mut LoweringContext,
// match Carrier::translate(<expr>) {
// Ok(val) => #[allow(unreachable_code)] val,
// Err(err) => #[allow(unreachable_code)]
// // If there is an enclosing `catch {...}`
// break 'catch_target Carrier::from_error(From::from(err)),
// // Otherwise
// return Carrier::from_error(From::from(err)),
// }
// FIXME(cramertj): implement breaking to catch
if
!
self
.catch_scopes
.is_empty
()
{
bug!
(
"`?` in catch scopes is unimplemented"
)
}
let
unstable_span
=
self
.allow_internal_unstable
(
"?"
,
e
.span
);
// Carrier::translate(<expr>)
...
...
@@ -2157,9 +2163,24 @@ fn make_struct(this: &mut LoweringContext,
P
(
self
.expr_call
(
e
.span
,
from_err
,
hir_vec!
[
from_expr
]))
};
let
ret_expr
=
P
(
self
.expr
(
e
.span
,
hir
::
Expr_
::
ExprRet
(
Some
(
from_err_expr
)),
ThinVec
::
from
(
attrs
)));
let
thin_attrs
=
ThinVec
::
from
(
attrs
);
let
catch_scope
=
self
.catch_scopes
.last
()
.map
(|
x
|
*
x
);
let
ret_expr
=
if
let
Some
(
catch_node
)
=
catch_scope
{
P
(
self
.expr
(
e
.span
,
hir
::
ExprBreak
(
hir
::
Destination
{
ident
:
None
,
target_id
:
hir
::
ScopeTarget
::
Block
(
catch_node
),
},
Some
(
from_err_expr
)
),
thin_attrs
))
}
else
{
P
(
self
.expr
(
e
.span
,
hir
::
Expr_
::
ExprRet
(
Some
(
from_err_expr
)),
thin_attrs
))
};
let
err_pat
=
self
.pat_err
(
e
.span
,
err_local
);
self
.arm
(
hir_vec!
[
err_pat
],
ret_expr
)
...
...
@@ -2302,7 +2323,7 @@ fn field(&mut self, name: Name, expr: P<hir::Expr>, span: Span) -> hir::Field {
}
fn
expr_break
(
&
mut
self
,
span
:
Span
,
attrs
:
ThinVec
<
Attribute
>
)
->
P
<
hir
::
Expr
>
{
let
expr_break
=
hir
::
ExprBreak
(
self
.lower_destination
(
None
),
None
);
let
expr_break
=
hir
::
ExprBreak
(
self
.lower_
loop_
destination
(
None
),
None
);
P
(
self
.expr
(
span
,
expr_break
,
attrs
))
}
...
...
@@ -2415,6 +2436,7 @@ fn block_all(&mut self, span: Span, stmts: hir::HirVec<hir::Stmt>, expr: Option<
id
:
self
.next_id
(),
rules
:
hir
::
DefaultBlock
,
span
:
span
,
break_to_expr_id
:
None
,
}
}
...
...
@@ -2519,6 +2541,7 @@ fn signal_block_expr(&mut self,
id
:
id
,
stmts
:
stmts
,
expr
:
Some
(
expr
),
break_to_expr_id
:
None
,
});
self
.expr_block
(
block
,
attrs
)
}
...
...
src/librustc/hir/mod.rs
浏览文件 @
fc04eaac
...
...
@@ -485,6 +485,9 @@ pub struct Block {
/// Distinguishes between `unsafe { ... }` and `{ ... }`
pub
rules
:
BlockCheckMode
,
pub
span
:
Span
,
/// The id of the expression that `break` breaks to if the block can be broken out of.
/// Currently only `Some(_)` for `catch {}` blocks
pub
break_to_expr_id
:
Option
<
NodeId
>
,
}
#[derive(Clone,
PartialEq,
Eq,
RustcEncodable,
RustcDecodable,
Hash)]
...
...
@@ -1080,6 +1083,22 @@ fn from(res: Result<NodeId, LoopIdError>) -> Self {
}
}
#[derive(Clone,
PartialEq,
Eq,
RustcEncodable,
RustcDecodable,
Hash,
Debug,
Copy)]
pub
enum
ScopeTarget
{
Block
(
NodeId
),
Loop
(
LoopIdResult
),
}
impl
ScopeTarget
{
pub
fn
opt_id
(
self
)
->
Option
<
NodeId
>
{
match
self
{
ScopeTarget
::
Block
(
node_id
)
|
ScopeTarget
::
Loop
(
LoopIdResult
::
Ok
(
node_id
))
=>
Some
(
node_id
),
ScopeTarget
::
Loop
(
LoopIdResult
::
Err
(
_
))
=>
None
,
}
}
}
#[derive(Clone,
PartialEq,
Eq,
RustcEncodable,
RustcDecodable,
Hash,
Debug,
Copy)]
pub
struct
Destination
{
// This is `Some(_)` iff there is an explicit user-specified `label
...
...
@@ -1087,7 +1106,7 @@ pub struct Destination {
// These errors are caught and then reported during the diagnostics pass in
// librustc_passes/loops.rs
pub
loop_id
:
LoopIdResul
t
,
pub
target_id
:
ScopeTarge
t
,
}
#[derive(Clone,
PartialEq,
Eq,
RustcEncodable,
RustcDecodable,
Hash,
Debug,
Copy)]
...
...
src/librustc/middle/liveness.rs
浏览文件 @
fc04eaac
...
...
@@ -516,14 +516,15 @@ struct Liveness<'a, 'tcx: 'a> {
s
:
Specials
,
successors
:
Vec
<
LiveNode
>
,
users
:
Vec
<
Users
>
,
// The list of node IDs for the nested loop scopes
// we're in.
loop_scope
:
Vec
<
NodeId
>
,
// mappings from loop node ID to LiveNode
// ("break" label should map to loop node ID,
// it probably doesn't now)
break_ln
:
NodeMap
<
LiveNode
>
,
cont_ln
:
NodeMap
<
LiveNode
>
cont_ln
:
NodeMap
<
LiveNode
>
,
// mappings from node ID to LiveNode for "breakable" blocks-- currently only `catch {...}`
breakable_block_ln
:
NodeMap
<
LiveNode
>
,
}
impl
<
'a
,
'tcx
>
Liveness
<
'a
,
'tcx
>
{
...
...
@@ -550,9 +551,9 @@ fn new(ir: &'a mut IrMaps<'a, 'tcx>, body: hir::BodyId) -> Liveness<'a, 'tcx> {
s
:
specials
,
successors
:
vec!
[
invalid_node
();
num_live_nodes
],
users
:
vec!
[
invalid_users
();
num_live_nodes
*
num_vars
],
loop_scope
:
Vec
::
new
(),
break_ln
:
NodeMap
(),
cont_ln
:
NodeMap
(),
breakable_block_ln
:
NodeMap
(),
}
}
...
...
@@ -793,15 +794,17 @@ fn compute(&mut self, body: &hir::Expr) -> LiveNode {
debug!
(
"compute: using id for body, {}"
,
self
.ir.tcx.hir
.node_to_pretty_string
(
body
.id
));
let
exit_ln
=
self
.s.exit_ln
;
let
entry_ln
:
LiveNode
=
self
.with_loop_nodes
(
body
.id
,
exit_ln
,
exit_ln
,
|
this
|
{
// the fallthrough exit is only for those cases where we do not
// explicitly return:
let
s
=
this
.s
;
this
.init_from_succ
(
s
.fallthrough_ln
,
s
.exit_ln
);
this
.acc
(
s
.fallthrough_ln
,
s
.clean_exit_var
,
ACC_READ
);
this
.propagate_through_expr
(
body
,
s
.fallthrough_ln
)
});
self
.break_ln
.insert
(
body
.id
,
exit_ln
);
self
.cont_ln
.insert
(
body
.id
,
exit_ln
);
// the fallthrough exit is only for those cases where we do not
// explicitly return:
let
s
=
self
.s
;
self
.init_from_succ
(
s
.fallthrough_ln
,
s
.exit_ln
);
self
.acc
(
s
.fallthrough_ln
,
s
.clean_exit_var
,
ACC_READ
);
let
entry_ln
=
self
.propagate_through_expr
(
body
,
s
.fallthrough_ln
);
// hack to skip the loop unless debug! is enabled:
debug!
(
"^^ liveness computation results for body {} (entry={:?})"
,
...
...
@@ -818,6 +821,9 @@ fn compute(&mut self, body: &hir::Expr) -> LiveNode {
fn
propagate_through_block
(
&
mut
self
,
blk
:
&
hir
::
Block
,
succ
:
LiveNode
)
->
LiveNode
{
if
let
Some
(
break_to_expr_id
)
=
blk
.break_to_expr_id
{
self
.breakable_block_ln
.insert
(
break_to_expr_id
,
succ
);
}
let
succ
=
self
.propagate_through_opt_expr
(
blk
.expr
.as_ref
()
.map
(|
e
|
&**
e
),
succ
);
blk
.stmts
.iter
()
.rev
()
.fold
(
succ
,
|
succ
,
stmt
|
{
self
.propagate_through_stmt
(
stmt
,
succ
)
...
...
@@ -901,30 +907,32 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
}
hir
::
ExprClosure
(
..
,
blk_id
,
_
)
=>
{
debug!
(
"{} is an ExprClosure"
,
self
.ir.tcx.hir
.node_to_pretty_string
(
expr
.id
));
debug!
(
"{} is an ExprClosure"
,
self
.ir.tcx.hir
.node_to_pretty_string
(
expr
.id
));
/*
The next-node for a break is the successor of the entire
loop. The next-node for a continue is the top of this loop.
*/
let
node
=
self
.live_node
(
expr
.id
,
expr
.span
);
self
.with_loop_nodes
(
blk_id
.node_id
,
succ
,
node
,
|
this
|
{
// the construction of a closure itself is not important,
// but we have to consider the closed over variables.
let
caps
=
match
this
.ir.capture_info_map
.get
(
&
expr
.id
)
{
Some
(
caps
)
=>
caps
.clone
(),
None
=>
{
span_bug!
(
expr
.span
,
"no registered caps"
);
}
};
caps
.iter
()
.rev
()
.fold
(
succ
,
|
succ
,
cap
|
{
this
.init_from_succ
(
cap
.ln
,
succ
);
let
var
=
this
.variable
(
cap
.var_nid
,
expr
.span
);
this
.acc
(
cap
.ln
,
var
,
ACC_READ
|
ACC_USE
);
cap
.ln
})
let
break_ln
=
succ
;
let
cont_ln
=
node
;
self
.break_ln
.insert
(
blk_id
.node_id
,
break_ln
);
self
.cont_ln
.insert
(
blk_id
.node_id
,
cont_ln
);
// the construction of a closure itself is not important,
// but we have to consider the closed over variables.
let
caps
=
match
self
.ir.capture_info_map
.get
(
&
expr
.id
)
{
Some
(
caps
)
=>
caps
.clone
(),
None
=>
{
span_bug!
(
expr
.span
,
"no registered caps"
);
}
};
caps
.iter
()
.rev
()
.fold
(
succ
,
|
succ
,
cap
|
{
self
.init_from_succ
(
cap
.ln
,
succ
);
let
var
=
self
.variable
(
cap
.var_nid
,
expr
.span
);
self
.acc
(
cap
.ln
,
var
,
ACC_READ
|
ACC_USE
);
cap
.ln
})
}
...
...
@@ -1003,28 +1011,33 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
hir
::
ExprBreak
(
label
,
ref
opt_expr
)
=>
{
// Find which label this break jumps to
let
sc
=
match
label
.loop_id
.into
()
{
Ok
(
loop_id
)
=>
loop_id
,
Err
(
err
)
=>
span_bug!
(
expr
.span
,
"loop scope error: {}"
,
err
),
};
let
target
=
match
label
.target_id
{
hir
::
ScopeTarget
::
Block
(
node_id
)
=>
self
.breakable_block_ln
.get
(
&
node_id
),
hir
::
ScopeTarget
::
Loop
(
hir
::
LoopIdResult
::
Ok
(
node_id
))
=>
self
.break_ln
.get
(
&
node_id
),
hir
::
ScopeTarget
::
Loop
(
hir
::
LoopIdResult
::
Err
(
err
))
=>
span_bug!
(
expr
.span
,
"loop scope error: {}"
,
err
),
}
.map
(|
x
|
*
x
);
// Now that we know the label we're going to,
// look it up in the break loop nodes table
match
self
.break_ln
.get
(
&
sc
)
{
Some
(
&
b
)
=>
self
.propagate_through_opt_expr
(
opt_expr
.as_ref
()
.map
(|
e
|
&**
e
),
b
),
match
target
{
Some
(
b
)
=>
self
.propagate_through_opt_expr
(
opt_expr
.as_ref
()
.map
(|
e
|
&**
e
),
b
),
None
=>
span_bug!
(
expr
.span
,
"break to unknown label"
)
}
}
hir
::
ExprAgain
(
label
)
=>
{
// Find which label this expr continues to
let
sc
=
match
label
.loop_id
.into
()
{
Ok
(
loop_id
)
=>
loop_id
,
Err
(
err
)
=>
span_bug!
(
expr
.span
,
"loop scope error: {}"
,
err
),
let
sc
=
match
label
.target_id
{
hir
::
ScopeTarget
::
Block
(
_
)
=>
bug!
(
"can't `continue` to a non-loop block"
),
hir
::
ScopeTarget
::
Loop
(
hir
::
LoopIdResult
::
Ok
(
node_id
))
=>
node_id
,
hir
::
ScopeTarget
::
Loop
(
hir
::
LoopIdResult
::
Err
(
err
))
=>
span_bug!
(
expr
.span
,
"loop scope error: {}"
,
err
),
};
// Now that we know the label we're going to,
// look it up in the continue loop nodes table
...
...
@@ -1287,14 +1300,16 @@ fn propagate_through_loop(&mut self,
debug!
(
"propagate_through_loop: using id for loop body {} {}"
,
expr
.id
,
self
.ir.tcx.hir
.node_to_pretty_string
(
body
.id
));
let
(
cond_ln
,
body_ln
)
=
self
.with_loop_nodes
(
expr
.id
,
succ
,
ln
,
|
this
|
{
let
cond_ln
=
match
kind
{
LoopLoop
=>
ln
,
WhileLoop
(
ref
cond
)
=>
this
.propagate_through_expr
(
&
cond
,
ln
),
};
let
body_ln
=
this
.propagate_through_block
(
body
,
cond_ln
);
(
cond_ln
,
body_ln
)
});
let
break_ln
=
succ
;
let
cont_ln
=
ln
;
self
.break_ln
.insert
(
expr
.id
,
break_ln
);
self
.cont_ln
.insert
(
expr
.id
,
cont_ln
);
let
cond_ln
=
match
kind
{
LoopLoop
=>
ln
,
WhileLoop
(
ref
cond
)
=>
self
.propagate_through_expr
(
&
cond
,
ln
),
};
let
body_ln
=
self
.propagate_through_block
(
body
,
cond_ln
);
// repeat until fixed point is reached:
while
self
.merge_from_succ
(
ln
,
body_ln
,
first_merge
)
{
...
...
@@ -1307,29 +1322,11 @@ fn propagate_through_loop(&mut self,
}
};
assert
!
(
cond_ln
==
new_cond_ln
);
assert
!
(
body_ln
==
self
.with_loop_nodes
(
expr
.id
,
succ
,
ln
,
|
this
|
this
.propagate_through_block
(
body
,
cond_ln
)));
assert
!
(
body_ln
==
self
.propagate_through_block
(
body
,
cond_ln
));
}
cond_ln
}
fn
with_loop_nodes
<
R
,
F
>
(
&
mut
self
,
loop_node_id
:
NodeId
,
break_ln
:
LiveNode
,
cont_ln
:
LiveNode
,
f
:
F
)
->
R
where
F
:
FnOnce
(
&
mut
Liveness
<
'a
,
'tcx
>
)
->
R
,
{
debug!
(
"with_loop_nodes: {} {}"
,
loop_node_id
,
break_ln
.get
());
self
.loop_scope
.push
(
loop_node_id
);
self
.break_ln
.insert
(
loop_node_id
,
break_ln
);
self
.cont_ln
.insert
(
loop_node_id
,
cont_ln
);
let
r
=
f
(
self
);
self
.loop_scope
.pop
();
r
}
}
// _______________________________________________________________________
...
...
src/librustc_mir/build/expr/into.rs
浏览文件 @
fc04eaac
...
...
@@ -40,7 +40,19 @@ pub fn into_expr(&mut self,
this
.in_scope
(
extent
,
block
,
|
this
|
this
.into
(
destination
,
block
,
value
))
}
ExprKind
::
Block
{
body
:
ast_block
}
=>
{
this
.ast_block
(
destination
,
block
,
ast_block
)
if
let
Some
(
_
)
=
ast_block
.break_to_expr_id
{
// This is a `break`-able block (currently only `catch { ... }`)
let
exit_block
=
this
.cfg
.start_new_block
();
let
block_exit
=
this
.in_breakable_scope
(
None
,
exit_block
,
destination
.clone
(),
|
this
|
{
this
.ast_block
(
destination
,
block
,
ast_block
)
});
this
.cfg
.terminate
(
unpack!
(
block_exit
),
source_info
,
TerminatorKind
::
Goto
{
target
:
exit_block
});
exit_block
.unit
()
}
else
{
this
.ast_block
(
destination
,
block
,
ast_block
)
}
}
ExprKind
::
Match
{
discriminant
,
arms
}
=>
{
this
.match_expr
(
destination
,
expr_span
,
block
,
discriminant
,
arms
)
...
...
@@ -165,8 +177,8 @@ pub fn into_expr(&mut self,
this
.cfg
.terminate
(
block
,
source_info
,
TerminatorKind
::
Goto
{
target
:
loop_block
});
this
.in_
loop
_scope
(
loop_block
,
exit_block
,
destination
.clone
(),
this
.in_
breakable
_scope
(
Some
(
loop_block
)
,
exit_block
,
destination
.clone
(),
move
|
this
|
{
// conduct the test, if necessary
let
body_block
;
...
...
src/librustc_mir/build/expr/stmt.rs
浏览文件 @
fc04eaac
...
...
@@ -9,7 +9,7 @@
// except according to those terms.
use
build
::{
BlockAnd
,
BlockAndExtension
,
Builder
};
use
build
::
scope
::
Loop
Scope
;
use
build
::
scope
::
Breakable
Scope
;
use
hair
::
*
;
use
rustc
::
mir
::
*
;
...
...
@@ -77,19 +77,21 @@ pub fn stmt_expr(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd
block
.unit
()
}
ExprKind
::
Continue
{
label
}
=>
{
let
LoopScope
{
continue_block
,
extent
,
..
}
=
*
this
.find_loop_scope
(
expr_span
,
label
);
let
BreakableScope
{
continue_block
,
extent
,
..
}
=
*
this
.find_breakable_scope
(
expr_span
,
label
);
let
continue_block
=
continue_block
.expect
(
"Attempted to continue in non-continuable breakable block"
);
this
.exit_scope
(
expr_span
,
extent
,
block
,
continue_block
);
this
.cfg
.start_new_block
()
.unit
()
}
ExprKind
::
Break
{
label
,
value
}
=>
{
let
(
break_block
,
extent
,
destination
)
=
{
let
Loop
Scope
{
let
Breakable
Scope
{
break_block
,
extent
,
ref
break_destination
,
..
}
=
*
this
.find_
loop
_scope
(
expr_span
,
label
);
}
=
*
this
.find_
breakable
_scope
(
expr_span
,
label
);
(
break_block
,
extent
,
break_destination
.clone
())
};
if
let
Some
(
value
)
=
value
{
...
...
src/librustc_mir/build/mod.rs
浏览文件 @
fc04eaac
...
...
@@ -36,9 +36,9 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
/// see the `scope` module for more details
scopes
:
Vec
<
scope
::
Scope
<
'tcx
>>
,
/// the current set of
loop
s; see the `scope` module for more
/// the current set of
breakable
s; see the `scope` module for more
/// details
loop_scopes
:
Vec
<
scope
::
Loop
Scope
<
'tcx
>>
,
breakable_scopes
:
Vec
<
scope
::
Breakable
Scope
<
'tcx
>>
,
/// the vector of all scopes that we have created thus far;
/// we track this for debuginfo later
...
...
@@ -248,7 +248,7 @@ fn new(hir: Cx<'a, 'gcx, 'tcx>,
scopes
:
vec!
[],
visibility_scopes
:
IndexVec
::
new
(),
visibility_scope
:
ARGUMENT_VISIBILITY_SCOPE
,
loop
_scopes
:
vec!
[],
breakable
_scopes
:
vec!
[],
local_decls
:
IndexVec
::
from_elem_n
(
LocalDecl
::
new_return_pointer
(
return_ty
),
1
),
var_indices
:
NodeMap
(),
unit_temp
:
None
,
...
...
src/librustc_mir/build/scope.rs
浏览文件 @
fc04eaac
...
...
@@ -177,16 +177,16 @@ struct FreeData<'tcx> {
}
#[derive(Clone,
Debug)]
pub
struct
Loop
Scope
<
'tcx
>
{
pub
struct
Breakable
Scope
<
'tcx
>
{
/// Extent of the loop
pub
extent
:
CodeExtent
,
/// Where the body of the loop begins
pub
continue_block
:
BasicBlock
,
/// Block to branch into when the loop
terminates (either by being `break`-en out from, or by
/// having its condition to become false)
/// Where the body of the loop begins
. `None` if block
pub
continue_block
:
Option
<
BasicBlock
>
,
/// Block to branch into when the loop
or block terminates (either by being `break`-en out
///
from, or by
having its condition to become false)
pub
break_block
:
BasicBlock
,
/// The destination of the loop
expression itself (i.e. where to put the result of a `break`
/// expression)
/// The destination of the loop
/block expression itself (i.e. where to put the result of a
///
`break`
expression)
pub
break_destination
:
Lvalue
<
'tcx
>
,
}
...
...
@@ -242,28 +242,29 @@ fn source_info(&self, span: Span) -> SourceInfo {
impl
<
'a
,
'gcx
,
'tcx
>
Builder
<
'a
,
'gcx
,
'tcx
>
{
// Adding and removing scopes
// ==========================
/// Start a
loop
scope, which tracks where `continue` and `break`
/// Start a
breakable
scope, which tracks where `continue` and `break`
/// should branch to. See module comment for more details.
///
/// Returns the might_break attribute of the
Loop
Scope used.
pub
fn
in_
loop_scope
<
F
>
(
&
mut
self
,
loop_block
:
BasicBlock
,
/// Returns the might_break attribute of the
Breakable
Scope used.
pub
fn
in_
breakable_scope
<
F
,
R
>
(
&
mut
self
,
loop_block
:
Option
<
BasicBlock
>
,
break_block
:
BasicBlock
,
break_destination
:
Lvalue
<
'tcx
>
,
f
:
F
)
where
F
:
FnOnce
(
&
mut
Builder
<
'a
,
'gcx
,
'tcx
>
)
f
:
F
)
->
R
where
F
:
FnOnce
(
&
mut
Builder
<
'a
,
'gcx
,
'tcx
>
)
->
R
{
let
extent
=
self
.topmost_scope
();
let
loop_scope
=
Loop
Scope
{
let
scope
=
Breakable
Scope
{
extent
:
extent
,
continue_block
:
loop_block
,
break_block
:
break_block
,
break_destination
:
break_destination
,
};
self
.loop_scopes
.push
(
loop_scope
);
f
(
self
);
let
loop_scope
=
self
.loop_scopes
.pop
()
.unwrap
();
assert
!
(
loop_scope
.extent
==
extent
);
self
.breakable_scopes
.push
(
scope
);
let
res
=
f
(
self
);
let
breakable_scope
=
self
.breakable_scopes
.pop
()
.unwrap
();
assert
!
(
breakable_scope
.extent
==
extent
);
res
}
/// Convenience wrapper that pushes a scope and then executes `f`
...
...
@@ -381,18 +382,18 @@ pub fn new_visibility_scope(&mut self, span: Span) -> VisibilityScope {
// Finding scopes
// ==============
/// Finds the
loop
scope for a given label. This is used for
/// Finds the
breakable
scope for a given label. This is used for
/// resolving `break` and `continue`.
pub
fn
find_
loop
_scope
(
&
mut
self
,
pub
fn
find_
breakable
_scope
(
&
mut
self
,
span
:
Span
,
label
:
CodeExtent
)
->
&
mut
Loop
Scope
<
'tcx
>
{
->
&
mut
Breakable
Scope
<
'tcx
>
{
// find the loop-scope with the correct id
self
.
loop
_scopes
.iter_mut
()
self
.
breakable
_scopes
.iter_mut
()
.rev
()
.filter
(|
loop_scope
|
loop
_scope
.extent
==
label
)
.filter
(|
breakable_scope
|
breakable
_scope
.extent
==
label
)
.next
()
.unwrap_or_else
(||
span_bug!
(
span
,
"no enclosing
loop scope found?
"
))
.unwrap_or_else
(||
span_bug!
(
span
,
"no enclosing
breakable scope found
"
))
}
/// Given a span and the current visibility scope, make a SourceInfo.
...
...
src/librustc_mir/hair/cx/expr.rs
浏览文件 @
fc04eaac
...
...
@@ -606,22 +606,25 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
}
}
hir
::
ExprRet
(
ref
v
)
=>
ExprKind
::
Return
{
value
:
v
.to_ref
()
},
hir
::
ExprBreak
(
label
,
ref
value
)
=>
{
match
label
.loop_id
.into
()
{
Ok
(
loop_id
)
=>
ExprKind
::
Break
{
label
:
cx
.tcx.region_maps
.node_extent
(
loop_id
),
hir
::
ExprBreak
(
dest
,
ref
value
)
=>
{
match
dest
.target_id
{
hir
::
ScopeTarget
::
Block
(
target_id
)
|
hir
::
ScopeTarget
::
Loop
(
hir
::
LoopIdResult
::
Ok
(
target_id
))
=>
ExprKind
::
Break
{
label
:
cx
.tcx.region_maps
.node_extent
(
target_id
),
value
:
value
.to_ref
(),
},
Err
(
err
)
=>
bug!
(
"invalid loop id for break: {}"
,
err
)
hir
::
ScopeTarget
::
Loop
(
hir
::
LoopIdResult
::
Err
(
err
))
=>
bug!
(
"invalid loop id for break: {}"
,
err
)
}
}
hir
::
ExprAgain
(
label
)
=>
{
match
label
.loop_id
.into
()
{
Ok
(
loop_id
)
=>
ExprKind
::
Continue
{
hir
::
ExprAgain
(
dest
)
=>
{
match
dest
.target_id
{
hir
::
ScopeTarget
::
Block
(
_
)
=>
bug!
(
"cannot continue to blocks"
),
hir
::
ScopeTarget
::
Loop
(
hir
::
LoopIdResult
::
Ok
(
loop_id
))
=>
ExprKind
::
Continue
{
label
:
cx
.tcx.region_maps
.node_extent
(
loop_id
),
},
Err
(
err
)
=>
bug!
(
"invalid loop id for continue: {}"
,
err
)
hir
::
ScopeTarget
::
Loop
(
hir
::
LoopIdResult
::
Err
(
err
))
=>
bug!
(
"invalid loop id for continue: {}"
,
err
)
}
}
hir
::
ExprMatch
(
ref
discr
,
ref
arms
,
_
)
=>
{
...
...
src/librustc_passes/loops.rs
浏览文件 @
fc04eaac
...
...
@@ -87,14 +87,19 @@ fn visit_expr(&mut self, e: &'hir hir::Expr) {
self
.with_context
(
Closure
,
|
v
|
v
.visit_nested_body
(
b
));
}
hir
::
ExprBreak
(
label
,
ref
opt_expr
)
=>
{
let
loop_id
=
match
label
.loop_id
.into
()
{
Ok
(
loop_id
)
=>
loop_id
,
Err
(
hir
::
LoopIdError
::
OutsideLoopScope
)
=>
ast
::
DUMMY_NODE_ID
,
Err
(
hir
::
LoopIdError
::
UnlabeledCfInWhileCondition
)
=>
{
self
.emit_unlabled_cf_in_while_condition
(
e
.span
,
"break"
);
ast
::
DUMMY_NODE_ID
},
Err
(
hir
::
LoopIdError
::
UnresolvedLabel
)
=>
ast
::
DUMMY_NODE_ID
,
let
loop_id
=
match
label
.target_id
{
hir
::
ScopeTarget
::
Block
(
_
)
=>
return
,
hir
::
ScopeTarget
::
Loop
(
loop_res
)
=>
{
match
loop_res
.into
()
{
Ok
(
loop_id
)
=>
loop_id
,
Err
(
hir
::
LoopIdError
::
OutsideLoopScope
)
=>
ast
::
DUMMY_NODE_ID
,
Err
(
hir
::
LoopIdError
::
UnlabeledCfInWhileCondition
)
=>
{
self
.emit_unlabled_cf_in_while_condition
(
e
.span
,
"break"
);
ast
::
DUMMY_NODE_ID
},
Err
(
hir
::
LoopIdError
::
UnresolvedLabel
)
=>
ast
::
DUMMY_NODE_ID
,
}
}
};
if
opt_expr
.is_some
()
{
...
...
@@ -124,7 +129,9 @@ fn visit_expr(&mut self, e: &'hir hir::Expr) {
self
.require_loop
(
"break"
,
e
.span
);
}
hir
::
ExprAgain
(
label
)
=>
{
if
let
Err
(
hir
::
LoopIdError
::
UnlabeledCfInWhileCondition
)
=
label
.loop_id
.into
()
{
if
let
hir
::
ScopeTarget
::
Loop
(
hir
::
LoopIdResult
::
Err
(
hir
::
LoopIdError
::
UnlabeledCfInWhileCondition
))
=
label
.target_id
{
self
.emit_unlabled_cf_in_while_condition
(
e
.span
,
"continue"
);
}
self
.require_loop
(
"continue"
,
e
.span
)
...
...
src/librustc_typeck/check/mod.rs
浏览文件 @
fc04eaac
...
...
@@ -402,7 +402,7 @@ fn always(self) -> bool {
}
#[derive(Clone)]
pub
struct
Loop
Ctxt
<
'gcx
,
'tcx
>
{
pub
struct
Breakable
Ctxt
<
'gcx
,
'tcx
>
{
unified
:
Ty
<
'tcx
>
,
coerce_to
:
Ty
<
'tcx
>
,
break_exprs
:
Vec
<&
'gcx
hir
::
Expr
>
,
...
...
@@ -410,15 +410,17 @@ pub struct LoopCtxt<'gcx, 'tcx> {
}
#[derive(Clone)]
pub
struct
Enclosing
Loop
s
<
'gcx
,
'tcx
>
{
stack
:
Vec
<
Loop
Ctxt
<
'gcx
,
'tcx
>>
,
pub
struct
Enclosing
Breakable
s
<
'gcx
,
'tcx
>
{
stack
:
Vec
<
Breakable
Ctxt
<
'gcx
,
'tcx
>>
,
by_id
:
NodeMap
<
usize
>
,
}
impl
<
'gcx
,
'tcx
>
EnclosingLoops
<
'gcx
,
'tcx
>
{
fn
find_loop
(
&
mut
self
,
id
:
hir
::
LoopIdResult
)
->
Option
<&
mut
LoopCtxt
<
'gcx
,
'tcx
>>
{
let
id_res
:
Result
<
_
,
_
>
=
id
.into
();
if
let
Some
(
ix
)
=
id_res
.ok
()
.and_then
(|
id
|
self
.by_id
.get
(
&
id
)
.cloned
())
{
impl
<
'gcx
,
'tcx
>
EnclosingBreakables
<
'gcx
,
'tcx
>
{
fn
find_breakable
(
&
mut
self
,
target
:
hir
::
ScopeTarget
)
->
Option
<&
mut
BreakableCtxt
<
'gcx
,
'tcx
>>
{
let
opt_index
=
target
.opt_id
()
.and_then
(|
id
|
self
.by_id
.get
(
&
id
)
.cloned
());
if
let
Some
(
ix
)
=
opt_index
{
Some
(
&
mut
self
.stack
[
ix
])
}
else
{
None
...
...
@@ -448,7 +450,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
/// Whether any child nodes have any type errors.
has_errors
:
Cell
<
bool
>
,
enclosing_
loops
:
RefCell
<
EnclosingLoop
s
<
'gcx
,
'tcx
>>
,
enclosing_
breakables
:
RefCell
<
EnclosingBreakable
s
<
'gcx
,
'tcx
>>
,
inh
:
&
'a
Inherited
<
'a
,
'gcx
,
'tcx
>
,
}
...
...
@@ -1429,7 +1431,7 @@ pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>,
ast
::
CRATE_NODE_ID
)),
diverges
:
Cell
::
new
(
Diverges
::
Maybe
),
has_errors
:
Cell
::
new
(
false
),
enclosing_
loops
:
RefCell
::
new
(
EnclosingLoop
s
{
enclosing_
breakables
:
RefCell
::
new
(
EnclosingBreakable
s
{
stack
:
Vec
::
new
(),
by_id
:
NodeMap
(),
}),
...
...
@@ -3467,10 +3469,11 @@ fn check_expr_kind(&self,
}
tcx
.mk_nil
()
}
hir
::
ExprBreak
(
label
,
ref
expr_opt
)
=>
{
hir
::
ExprBreak
(
destination
,
ref
expr_opt
)
=>
{
let
coerce_to
=
{
let
mut
enclosing_loops
=
self
.enclosing_loops
.borrow_mut
();
enclosing_loops
.find_loop
(
label
.loop_id
)
.map
(|
ctxt
|
ctxt
.coerce_to
)
let
mut
enclosing_breakables
=
self
.enclosing_breakables
.borrow_mut
();
enclosing_breakables
.find_breakable
(
destination
.target_id
)
.map
(|
ctxt
|
ctxt
.coerce_to
)
};
if
let
Some
(
coerce_to
)
=
coerce_to
{
let
e_ty
;
...
...
@@ -3486,8 +3489,8 @@ fn check_expr_kind(&self,
cause
=
self
.misc
(
expr
.span
);
}
let
mut
enclosing_
loops
=
self
.enclosing_loop
s
.borrow_mut
();
let
ctxt
=
enclosing_
loops
.find_loop
(
label
.loop
_id
)
.unwrap
();
let
mut
enclosing_
breakables
=
self
.enclosing_breakable
s
.borrow_mut
();
let
ctxt
=
enclosing_
breakables
.find_breakable
(
destination
.target
_id
)
.unwrap
();
let
result
=
if
let
Some
(
ref
e
)
=
*
expr_opt
{
// Special-case the first element, as it has no "previous expressions".
...
...
@@ -3517,8 +3520,9 @@ fn check_expr_kind(&self,
ctxt
.may_break
=
true
;
}
// Otherwise, we failed to find the enclosing loop; this can only happen if the
// `break` was not inside a loop at all, which is caught by the loop-checking pass.
// Otherwise, we failed to find the enclosing breakable; this can only happen if the
// `break` target was not found, which is caught in HIR lowering and reported by the
// loop-checking pass.
tcx
.types.never
}
hir
::
ExprAgain
(
_
)
=>
{
tcx
.types.never
}
...
...
@@ -3575,13 +3579,13 @@ fn check_expr_kind(&self,
hir
::
ExprWhile
(
ref
cond
,
ref
body
,
_
)
=>
{
let
unified
=
self
.tcx
.mk_nil
();
let
coerce_to
=
unified
;
let
ctxt
=
Loop
Ctxt
{
let
ctxt
=
Breakable
Ctxt
{
unified
:
unified
,
coerce_to
:
coerce_to
,
break_exprs
:
vec!
[],
may_break
:
true
,
};
self
.with_
loop
_ctxt
(
expr
.id
,
ctxt
,
||
{
self
.with_
breakable
_ctxt
(
expr
.id
,
ctxt
,
||
{
self
.check_expr_has_type
(
&
cond
,
tcx
.types.bool
);
let
cond_diverging
=
self
.diverges
.get
();
self
.check_block_no_value
(
&
body
);
...
...
@@ -3599,14 +3603,14 @@ fn check_expr_kind(&self,
hir
::
ExprLoop
(
ref
body
,
_
,
_
)
=>
{
let
unified
=
self
.next_ty_var
(
TypeVariableOrigin
::
TypeInference
(
body
.span
));
let
coerce_to
=
expected
.only_has_type
(
self
)
.unwrap_or
(
unified
);
let
ctxt
=
Loop
Ctxt
{
let
ctxt
=
Breakable
Ctxt
{
unified
:
unified
,
coerce_to
:
coerce_to
,
break_exprs
:
vec!
[],
may_break
:
false
,
};
let
ctxt
=
self
.with_loop
_ctxt
(
expr
.id
,
ctxt
,
||
{
let
(
ctxt
,
())
=
self
.with_breakable
_ctxt
(
expr
.id
,
ctxt
,
||
{
self
.check_block_no_value
(
&
body
);
});
if
ctxt
.may_break
{
...
...
@@ -3625,8 +3629,8 @@ fn check_expr_kind(&self,
hir
::
ExprClosure
(
capture
,
ref
decl
,
body_id
,
_
)
=>
{
self
.check_expr_closure
(
expr
,
capture
,
&
decl
,
body_id
,
expected
)
}
hir
::
ExprBlock
(
ref
b
)
=>
{
self
.check_block_with_expected
(
&
b
,
expected
)
hir
::
ExprBlock
(
ref
b
ody
)
=>
{
self
.check_block_with_expected
(
&
b
ody
,
expected
)
}
hir
::
ExprCall
(
ref
callee
,
ref
args
)
=>
{
self
.check_call
(
expr
,
&
callee
,
args
,
expected
)
...
...
@@ -4018,65 +4022,85 @@ fn check_block_with_expected(&self,
replace
(
&
mut
*
fcx_ps
,
unsafety_state
)
};
for
s
in
&
blk
.stmts
{
self
.check_stmt
(
s
);
}
let
mut
ty
=
if
let
Some
(
break_to_expr_id
)
=
blk
.break_to_expr_id
{
let
unified
=
self
.next_ty_var
(
TypeVariableOrigin
::
TypeInference
(
blk
.span
));
let
coerce_to
=
expected
.only_has_type
(
self
)
.unwrap_or
(
unified
);
let
ctxt
=
BreakableCtxt
{
unified
:
unified
,
coerce_to
:
coerce_to
,
break_exprs
:
vec!
[],
may_break
:
false
,
};
let
mut
ty
=
match
blk
.expr
{
Some
(
ref
e
)
=>
self
.check_expr_with_expectation
(
e
,
expected
),
None
=>
self
.tcx
.mk_nil
()
};
let
(
mut
ctxt
,
(
e_ty
,
cause
))
=
self
.with_breakable_ctxt
(
break_to_expr_id
,
ctxt
,
||
{
for
s
in
&
blk
.stmts
{
self
.check_stmt
(
s
);
}
let
coerce_to
=
{
let
mut
enclosing_breakables
=
self
.enclosing_breakables
.borrow_mut
();
enclosing_breakables
.find_breakable
(
hir
::
ScopeTarget
::
Block
(
break_to_expr_id
)
)
.unwrap
()
.coerce_to
};
let
e_ty
;
let
cause
;
match
blk
.expr
{
Some
(
ref
e
)
=>
{
e_ty
=
self
.check_expr_with_hint
(
e
,
coerce_to
);
cause
=
self
.misc
(
e
.span
);
},
None
=>
{
e_ty
=
self
.tcx
.mk_nil
();
cause
=
self
.misc
(
blk
.span
);
}
};
(
e_ty
,
cause
)
});
if
self
.diverges
.get
()
.always
()
{
ty
=
self
.next_diverging_ty_var
(
TypeVariableOrigin
::
DivergingBlockExpr
(
blk
.span
));
}
else
if
let
ExpectHasType
(
ety
)
=
expected
{
if
let
Some
(
ref
e
)
=
blk
.expr
{
// Coerce the tail expression to the right type.
self
.demand_coerce
(
e
,
ty
,
ety
);
let
result
=
if
!
ctxt
.may_break
{
self
.try_coerce
(
e
,
e_ty
,
ctxt
.coerce_to
)
}
else
{
self
.try_find_coercion_lub
(
&
cause
,
||
ctxt
.break_exprs
.iter
()
.cloned
(),
ctxt
.unified
,
e
,
e_ty
)
};
match
result
{
Ok
(
ty
)
=>
ctxt
.unified
=
ty
,
Err
(
err
)
=>
self
.report_mismatched_types
(
&
cause
,
ctxt
.unified
,
e_ty
,
err
)
.emit
(),
}
}
else
{
// We're not diverging and there's an expected type, which,
// in case it's not `()`, could result in an error higher-up.
// We have a chance to error here early and be more helpful.
let
cause
=
self
.misc
(
blk
.span
);
let
trace
=
TypeTrace
::
types
(
&
cause
,
false
,
ty
,
ety
);
match
self
.sub_types
(
false
,
&
cause
,
ty
,
ety
)
{
Ok
(
InferOk
{
obligations
,
..
})
=>
{
// FIXME(#32730) propagate obligations
assert
!
(
obligations
.is_empty
());
},
Err
(
err
)
=>
{
let
mut
err
=
self
.report_and_explain_type_error
(
trace
,
&
err
);
// Be helpful when the user wrote `{... expr;}` and
// taking the `;` off is enough to fix the error.
let
mut
extra_semi
=
None
;
if
let
Some
(
stmt
)
=
blk
.stmts
.last
()
{
if
let
hir
::
StmtSemi
(
ref
e
,
_
)
=
stmt
.node
{
if
self
.can_sub_types
(
self
.node_ty
(
e
.id
),
ety
)
.is_ok
()
{
extra_semi
=
Some
(
stmt
);
}
}
}
if
let
Some
(
last_stmt
)
=
extra_semi
{
let
original_span
=
original_sp
(
self
.tcx.sess
.codemap
(),
last_stmt
.span
,
blk
.span
);
let
span_semi
=
Span
{
lo
:
original_span
.hi
-
BytePos
(
1
),
hi
:
original_span
.hi
,
expn_id
:
original_span
.expn_id
};
err
.span_help
(
span_semi
,
"consider removing this semicolon:"
);
}
self
.check_block_no_expr
(
blk
,
self
.tcx
.mk_nil
(),
e_ty
);
};
err
.emit
();
}
}
ctxt
.unified
}
else
{
for
s
in
&
blk
.stmts
{
self
.check_stmt
(
s
);
}
// We already applied the type (and potentially errored),
// use the expected type to avoid further errors out.
ty
=
ety
;
}
let
mut
ty
=
match
blk
.expr
{
Some
(
ref
e
)
=>
self
.check_expr_with_expectation
(
e
,
expected
),
None
=>
self
.tcx
.mk_nil
()
};
if
self
.diverges
.get
()
.always
()
{
ty
=
self
.next_diverging_ty_var
(
TypeVariableOrigin
::
DivergingBlockExpr
(
blk
.span
));
}
else
if
let
ExpectHasType
(
ety
)
=
expected
{
if
let
Some
(
ref
e
)
=
blk
.expr
{
// Coerce the tail expression to the right type.
self
.demand_coerce
(
e
,
ty
,
ety
);
}
else
{
self
.check_block_no_expr
(
blk
,
ty
,
ety
);
}
// We already applied the type (and potentially errored),
// use the expected type to avoid further errors out.
ty
=
ety
;
}
ty
};
if
self
.has_errors
.get
()
||
ty
.references_error
()
{
ty
=
self
.tcx.types.err
...
...
@@ -4088,6 +4112,46 @@ fn check_block_with_expected(&self,
ty
}
pub
fn
check_block_no_expr
(
&
self
,
blk
:
&
'gcx
hir
::
Block
,
ty
:
Ty
<
'tcx
>
,
ety
:
Ty
<
'tcx
>
)
{
// We're not diverging and there's an expected type, which,
// in case it's not `()`, could result in an error higher-up.
// We have a chance to error here early and be more helpful.
let
cause
=
self
.misc
(
blk
.span
);
let
trace
=
TypeTrace
::
types
(
&
cause
,
false
,
ty
,
ety
);
match
self
.sub_types
(
false
,
&
cause
,
ty
,
ety
)
{
Ok
(
InferOk
{
obligations
,
..
})
=>
{
// FIXME(#32730) propagate obligations
assert
!
(
obligations
.is_empty
());
},
Err
(
err
)
=>
{
let
mut
err
=
self
.report_and_explain_type_error
(
trace
,
&
err
);
// Be helpful when the user wrote `{... expr;}` and
// taking the `;` off is enough to fix the error.
let
mut
extra_semi
=
None
;
if
let
Some
(
stmt
)
=
blk
.stmts
.last
()
{
if
let
hir
::
StmtSemi
(
ref
e
,
_
)
=
stmt
.node
{
if
self
.can_sub_types
(
self
.node_ty
(
e
.id
),
ety
)
.is_ok
()
{
extra_semi
=
Some
(
stmt
);
}
}
}
if
let
Some
(
last_stmt
)
=
extra_semi
{
let
original_span
=
original_sp
(
self
.tcx.sess
.codemap
(),
last_stmt
.span
,
blk
.span
);
let
span_semi
=
Span
{
lo
:
original_span
.hi
-
BytePos
(
1
),
hi
:
original_span
.hi
,
expn_id
:
original_span
.expn_id
};
err
.span_help
(
span_semi
,
"consider removing this semicolon:"
);
}
err
.emit
();
}
}
}
// Instantiates the given path, which must refer to an item with the given
// number of type parameters and type.
pub
fn
instantiate_value_path
(
&
self
,
...
...
@@ -4485,22 +4549,24 @@ pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
})
}
fn
with_loop_ctxt
<
F
:
FnOnce
()
>
(
&
self
,
id
:
ast
::
NodeId
,
ctxt
:
LoopCtxt
<
'gcx
,
'tcx
>
,
f
:
F
)
->
LoopCtxt
<
'gcx
,
'tcx
>
{
fn
with_breakable_ctxt
<
F
:
FnOnce
()
->
R
,
R
>
(
&
self
,
id
:
ast
::
NodeId
,
ctxt
:
BreakableCtxt
<
'gcx
,
'tcx
>
,
f
:
F
)
->
(
BreakableCtxt
<
'gcx
,
'tcx
>
,
R
)
{
let
index
;
{
let
mut
enclosing_loops
=
self
.enclosing_loops
.borrow_mut
();
index
=
enclosing_loops
.stack
.len
();
enclosing_loops
.by_id
.insert
(
id
,
index
);
enclosing_loops
.stack
.push
(
ctxt
);
}
f
();
{
let
mut
enclosing_loops
=
self
.enclosing_loops
.borrow_mut
();
debug_assert!
(
enclosing_loops
.stack
.len
()
==
index
+
1
);
enclosing_loops
.by_id
.remove
(
&
id
)
.expect
(
"missing loop context"
);
(
enclosing_loops
.stack
.pop
()
.expect
(
"missing loop context"
))
let
mut
enclosing_breakables
=
self
.enclosing_breakables
.borrow_mut
();
index
=
enclosing_breakables
.stack
.len
();
enclosing_breakables
.by_id
.insert
(
id
,
index
);
enclosing_breakables
.stack
.push
(
ctxt
);
}
let
result
=
f
();
let
ctxt
=
{
let
mut
enclosing_breakables
=
self
.enclosing_breakables
.borrow_mut
();
debug_assert!
(
enclosing_breakables
.stack
.len
()
==
index
+
1
);
enclosing_breakables
.by_id
.remove
(
&
id
)
.expect
(
"missing breakable context"
);
enclosing_breakables
.stack
.pop
()
.expect
(
"missing breakable context"
)
};
(
ctxt
,
result
)
}
}
...
...
src/test/compile-fail/catch-bad-lifetime.rs
0 → 100644
浏览文件 @
fc04eaac
// Copyright 2017 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(catch_expr)]
pub
fn
main
()
{
let
_
:
Result
<
(),
&
str
>
=
do
catch
{
let
my_string
=
String
::
from
(
""
);
let
my_str
:
&
str
=
&
my_string
;
Err
(
my_str
)
?
;
Err
(
""
)
?
;
Ok
(())
};
//~ ERROR `my_string` does not live long enough
let
mut
i
=
5
;
let
k
=
&
mut
i
;
let
mut
j
:
Result
<
(),
&
mut
i32
>
=
do
catch
{
Err
(
k
)
?
;
i
=
10
;
//~ ERROR cannot assign to `i` because it is borrowed
Ok
(())
};
::
std
::
mem
::
drop
(
k
);
//~ ERROR use of moved value: `k`
i
=
40
;
//~ ERROR cannot assign to `i` because it is borrowed
let
i_ptr
=
if
let
Err
(
i_ptr
)
=
j
{
i_ptr
}
else
{
panic!
(
""
)
};
*
i_ptr
=
50
;
}
src/test/compile-fail/catch-bad-type.rs
0 → 100644
浏览文件 @
fc04eaac
// Copyright 2017 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(catch_expr)]
pub
fn
main
()
{
let
res
:
Result
<
i32
,
i32
>
=
do
catch
{
Err
(
""
)
?
;
//~ ERROR the trait bound `i32: std::convert::From<&str>` is not satisfied
Ok
(
5
)
};
let
res
:
Result
<
i32
,
i32
>
=
do
catch
{
Ok
(
""
)
//~ mismatched types
};
}
src/test/compile-fail/catch-opt-init.rs
0 → 100644
浏览文件 @
fc04eaac
// Copyright 2017 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(catch_expr)]
pub
fn
main
()
{
let
cfg_res
;
let
_
:
Result
<
(),
()
>
=
do
catch
{
Err
(())
?
;
cfg_res
=
5
;
Ok
(())
};
assert_eq!
(
cfg_res
,
5
);
//~ ERROR use of possibly uninitialized variable
}
src/test/run-pass/catch-expr.rs
浏览文件 @
fc04eaac
...
...
@@ -29,4 +29,38 @@ pub fn main() {
match
catch
{
_
=>
{}
};
let
catch_err
=
do
catch
{
Err
(
22
)
?
;
Ok
(
1
)
};
assert_eq!
(
catch_err
,
Err
(
22
));
let
catch_okay
:
Result
<
i32
,
i32
>
=
do
catch
{
if
false
{
Err
(
25
)
?
;
}
Ok
::
<
(),
i32
>
(())
?
;
Ok
(
28
)
};
assert_eq!
(
catch_okay
,
Ok
(
28
));
let
catch_from_loop
:
Result
<
i32
,
i32
>
=
do
catch
{
for
i
in
0
..
10
{
if
i
<
5
{
Ok
::
<
i32
,
i32
>
(
i
)
?
;
}
else
{
Err
(
i
)
?
;
}
}
Ok
(
22
)
};
assert_eq!
(
catch_from_loop
,
Err
(
5
));
let
cfg_init
;
let
_
res
:
Result
<
(),
()
>
=
do
catch
{
cfg_init
=
5
;
Ok
(())
};
assert_eq!
(
cfg_init
,
5
);
let
my_string
=
"test"
.to_string
();
let
res
:
Result
<&
str
,
()
>
=
do
catch
{
Ok
(
&
my_string
)
};
assert_eq!
(
res
,
Ok
(
"test"
));
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录