Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
2bcc7591
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,发现更多精彩内容 >>
提交
2bcc7591
编写于
5月 21, 2021
作者:
F
Fabian Wolff
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Warn about unreachable code following an expression with an uninhabited type
上级
237b1ef0
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
200 addition
and
20 deletion
+200
-20
compiler/rustc_passes/src/liveness.rs
compiler/rustc_passes/src/liveness.rs
+91
-20
src/test/ui/lint/dead-code/issue-85071-2.rs
src/test/ui/lint/dead-code/issue-85071-2.rs
+22
-0
src/test/ui/lint/dead-code/issue-85071-2.stderr
src/test/ui/lint/dead-code/issue-85071-2.stderr
+34
-0
src/test/ui/lint/dead-code/issue-85071.rs
src/test/ui/lint/dead-code/issue-85071.rs
+19
-0
src/test/ui/lint/dead-code/issue-85071.stderr
src/test/ui/lint/dead-code/issue-85071.stderr
+34
-0
未找到文件。
compiler/rustc_passes/src/liveness.rs
浏览文件 @
2bcc7591
...
...
@@ -95,7 +95,7 @@
use
rustc_index
::
vec
::
IndexVec
;
use
rustc_middle
::
hir
::
map
::
Map
;
use
rustc_middle
::
ty
::
query
::
Providers
;
use
rustc_middle
::
ty
::{
self
,
DefIdTree
,
RootVariableMinCaptureList
,
TyCtxt
};
use
rustc_middle
::
ty
::{
self
,
DefIdTree
,
RootVariableMinCaptureList
,
Ty
,
Ty
Ctxt
};
use
rustc_session
::
lint
;
use
rustc_span
::
symbol
::{
kw
,
sym
,
Symbol
};
use
rustc_span
::
Span
;
...
...
@@ -123,8 +123,8 @@ pub struct LiveNode {
#[derive(Copy,
Clone,
PartialEq,
Debug)]
enum
LiveNodeKind
{
UpvarNode
(
Span
),
ExprNode
(
Span
),
VarDefNode
(
Span
),
ExprNode
(
Span
,
HirId
),
VarDefNode
(
Span
,
HirId
),
ClosureNode
,
ExitNode
,
}
...
...
@@ -133,8 +133,8 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String {
let
sm
=
tcx
.sess
.source_map
();
match
lnk
{
UpvarNode
(
s
)
=>
format!
(
"Upvar node [{}]"
,
sm
.span_to_diagnostic_string
(
s
)),
ExprNode
(
s
)
=>
format!
(
"Expr node [{}]"
,
sm
.span_to_diagnostic_string
(
s
)),
VarDefNode
(
s
)
=>
format!
(
"Var def node [{}]"
,
sm
.span_to_diagnostic_string
(
s
)),
ExprNode
(
s
,
_
)
=>
format!
(
"Expr node [{}]"
,
sm
.span_to_diagnostic_string
(
s
)),
VarDefNode
(
s
,
_
)
=>
format!
(
"Var def node [{}]"
,
sm
.span_to_diagnostic_string
(
s
)),
ClosureNode
=>
"Closure node"
.to_owned
(),
ExitNode
=>
"Exit node"
.to_owned
(),
}
...
...
@@ -297,7 +297,7 @@ fn add_from_pat(&mut self, pat: &hir::Pat<'tcx>) {
}
pat
.each_binding
(|
_
,
hir_id
,
_
,
ident
|
{
self
.add_live_node_for_node
(
hir_id
,
VarDefNode
(
ident
.span
));
self
.add_live_node_for_node
(
hir_id
,
VarDefNode
(
ident
.span
,
hir_id
));
self
.add_variable
(
Local
(
LocalInfo
{
id
:
hir_id
,
name
:
ident
.name
,
...
...
@@ -391,14 +391,14 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
hir
::
ExprKind
::
Path
(
hir
::
QPath
::
Resolved
(
_
,
ref
path
))
=>
{
debug!
(
"expr {}: path that leads to {:?}"
,
expr
.hir_id
,
path
.res
);
if
let
Res
::
Local
(
_
var_hir_id
)
=
path
.res
{
self
.add_live_node_for_node
(
expr
.hir_id
,
ExprNode
(
expr
.span
));
self
.add_live_node_for_node
(
expr
.hir_id
,
ExprNode
(
expr
.span
,
expr
.hir_id
));
}
intravisit
::
walk_expr
(
self
,
expr
);
}
hir
::
ExprKind
::
Closure
(
..
)
=>
{
// Interesting control flow (for loops can contain labeled
// breaks or continues)
self
.add_live_node_for_node
(
expr
.hir_id
,
ExprNode
(
expr
.span
));
self
.add_live_node_for_node
(
expr
.hir_id
,
ExprNode
(
expr
.span
,
expr
.hir_id
));
// Make a live_node for each captured variable, with the span
// being the location that the variable is used. This results
...
...
@@ -426,11 +426,11 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
// live nodes required for interesting control flow:
hir
::
ExprKind
::
If
(
..
)
|
hir
::
ExprKind
::
Match
(
..
)
|
hir
::
ExprKind
::
Loop
(
..
)
=>
{
self
.add_live_node_for_node
(
expr
.hir_id
,
ExprNode
(
expr
.span
));
self
.add_live_node_for_node
(
expr
.hir_id
,
ExprNode
(
expr
.span
,
expr
.hir_id
));
intravisit
::
walk_expr
(
self
,
expr
);
}
hir
::
ExprKind
::
Binary
(
op
,
..
)
if
op
.node
.is_lazy
()
=>
{
self
.add_live_node_for_node
(
expr
.hir_id
,
ExprNode
(
expr
.span
));
self
.add_live_node_for_node
(
expr
.hir_id
,
ExprNode
(
expr
.span
,
expr
.hir_id
));
intravisit
::
walk_expr
(
self
,
expr
);
}
...
...
@@ -978,11 +978,26 @@ fn propagate_through_expr(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNod
hir
::
ExprKind
::
Call
(
ref
f
,
ref
args
)
=>
{
let
m
=
self
.ir.tcx
.parent_module
(
expr
.hir_id
)
.to_def_id
();
let
succ
=
if
self
.ir.tcx
.is_ty_uninhabited_from
(
m
,
self
.typeck_results
.expr_ty
(
expr
),
self
.param_env
,
)
{
let
ty
=
self
.typeck_results
.expr_ty
(
expr
);
let
succ
=
if
self
.ir.tcx
.is_ty_uninhabited_from
(
m
,
ty
,
self
.param_env
)
{
if
let
LiveNodeKind
::
ExprNode
(
succ_span
,
succ_id
)
=
self
.ir.lnks
[
succ
]
{
self
.warn_about_unreachable
(
expr
.span
,
ty
,
succ_span
,
succ_id
,
"expression"
,
);
}
else
if
let
LiveNodeKind
::
VarDefNode
(
succ_span
,
succ_id
)
=
self
.ir.lnks
[
succ
]
{
self
.warn_about_unreachable
(
expr
.span
,
ty
,
succ_span
,
succ_id
,
"definition"
,
);
}
self
.exit_ln
}
else
{
succ
...
...
@@ -993,11 +1008,26 @@ fn propagate_through_expr(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNod
hir
::
ExprKind
::
MethodCall
(
..
,
ref
args
,
_
)
=>
{
let
m
=
self
.ir.tcx
.parent_module
(
expr
.hir_id
)
.to_def_id
();
let
succ
=
if
self
.ir.tcx
.is_ty_uninhabited_from
(
m
,
self
.typeck_results
.expr_ty
(
expr
),
self
.param_env
,
)
{
let
ty
=
self
.typeck_results
.expr_ty
(
expr
);
let
succ
=
if
self
.ir.tcx
.is_ty_uninhabited_from
(
m
,
ty
,
self
.param_env
)
{
if
let
LiveNodeKind
::
ExprNode
(
succ_span
,
succ_id
)
=
self
.ir.lnks
[
succ
]
{
self
.warn_about_unreachable
(
expr
.span
,
ty
,
succ_span
,
succ_id
,
"expression"
,
);
}
else
if
let
LiveNodeKind
::
VarDefNode
(
succ_span
,
succ_id
)
=
self
.ir.lnks
[
succ
]
{
self
.warn_about_unreachable
(
expr
.span
,
ty
,
succ_span
,
succ_id
,
"definition"
,
);
}
self
.exit_ln
}
else
{
succ
...
...
@@ -1274,6 +1304,47 @@ fn propagate_through_loop(
ln
}
fn
warn_about_unreachable
(
&
mut
self
,
orig_span
:
Span
,
orig_ty
:
Ty
<
'tcx
>
,
expr_span
:
Span
,
expr_id
:
HirId
,
descr
:
&
str
,
)
{
if
!
orig_ty
.is_never
()
{
// Unreachable code warnings are already emitted during type checking.
// However, during type checking, full type information is being
// calculated but not yet available, so the check for diverging
// expressions due to uninhabited result types is pretty crude and
// only checks whether ty.is_never(). Here, we have full type
// information available and can issue warnings for less obviously
// uninhabited types (e.g. empty enums). The check above is used so
// that we do not emit the same warning twice if the uninhabited type
// is indeed `!`.
self
.ir.tcx
.struct_span_lint_hir
(
lint
::
builtin
::
UNREACHABLE_CODE
,
expr_id
,
expr_span
,
|
lint
|
{
let
msg
=
format!
(
"unreachable {}"
,
descr
);
lint
.build
(
&
msg
)
.span_label
(
expr_span
,
&
msg
)
.span_label
(
orig_span
,
"any code following this expression is unreachable"
)
.span_note
(
orig_span
,
&
format!
(
"this expression has type `{}`, which is uninhabited"
,
orig_ty
),
)
.emit
();
},
);
}
}
}
// _______________________________________________________________________
...
...
src/test/ui/lint/dead-code/issue-85071-2.rs
0 → 100644
浏览文件 @
2bcc7591
// A slight variation of issue-85071.rs. Here, a method is called instead
// of a function, and the warning is about an unreachable definition
// instead of an unreachable expression.
// check-pass
#![warn(unused_variables,unreachable_code)]
enum
Foo
{}
struct
S
;
impl
S
{
fn
f
(
&
self
)
->
Foo
{
todo!
()}
}
fn
main
()
{
let
s
=
S
;
let
x
=
s
.f
();
//~^ WARNING: unused variable: `x`
let
_
y
=
x
;
//~^ WARNING: unreachable definition
}
src/test/ui/lint/dead-code/issue-85071-2.stderr
0 → 100644
浏览文件 @
2bcc7591
warning: unreachable definition
--> $DIR/issue-85071-2.rs:20:9
|
LL | let x = s.f();
| ----- any code following this expression is unreachable
LL |
LL | let _y = x;
| ^^ unreachable definition
|
note: the lint level is defined here
--> $DIR/issue-85071-2.rs:7:26
|
LL | #![warn(unused_variables,unreachable_code)]
| ^^^^^^^^^^^^^^^^
note: this expression has type `Foo`, which is uninhabited
--> $DIR/issue-85071-2.rs:18:13
|
LL | let x = s.f();
| ^^^^^
warning: unused variable: `x`
--> $DIR/issue-85071-2.rs:18:9
|
LL | let x = s.f();
| ^ help: if this is intentional, prefix it with an underscore: `_x`
|
note: the lint level is defined here
--> $DIR/issue-85071-2.rs:7:9
|
LL | #![warn(unused_variables,unreachable_code)]
| ^^^^^^^^^^^^^^^^
warning: 2 warnings emitted
src/test/ui/lint/dead-code/issue-85071.rs
0 → 100644
浏览文件 @
2bcc7591
// Checks that an unreachable code warning is emitted when an expression is
// preceded by an expression with an uninhabited type. Previously, the
// variable liveness analysis was "smarter" than the reachability analysis
// in this regard, which led to confusing "unused variable" warnings
// without an accompanying explanatory "unreachable expression" warning.
// check-pass
#![warn(unused_variables,unreachable_code)]
enum
Foo
{}
fn
f
()
->
Foo
{
todo!
()}
fn
main
()
{
let
x
=
f
();
//~^ WARNING: unused variable: `x`
let
_
=
x
;
//~^ WARNING: unreachable expression
}
src/test/ui/lint/dead-code/issue-85071.stderr
0 → 100644
浏览文件 @
2bcc7591
warning: unreachable expression
--> $DIR/issue-85071.rs:17:13
|
LL | let x = f();
| --- any code following this expression is unreachable
LL |
LL | let _ = x;
| ^ unreachable expression
|
note: the lint level is defined here
--> $DIR/issue-85071.rs:9:26
|
LL | #![warn(unused_variables,unreachable_code)]
| ^^^^^^^^^^^^^^^^
note: this expression has type `Foo`, which is uninhabited
--> $DIR/issue-85071.rs:15:13
|
LL | let x = f();
| ^^^
warning: unused variable: `x`
--> $DIR/issue-85071.rs:15:9
|
LL | let x = f();
| ^ help: if this is intentional, prefix it with an underscore: `_x`
|
note: the lint level is defined here
--> $DIR/issue-85071.rs:9:9
|
LL | #![warn(unused_variables,unreachable_code)]
| ^^^^^^^^^^^^^^^^
warning: 2 warnings emitted
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录