Skip to content

Commit 2e04872

Browse files
committed
Lint functions taking unhabited parameters with unreachable_code
1 parent 1409363 commit 2e04872

File tree

3 files changed

+66
-0
lines changed

3 files changed

+66
-0
lines changed

src/librustc_typeck/check/mod.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,11 +1082,19 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
10821082
GatherLocalsVisitor { fcx: &fcx, parent_id: outer_node_id, }.visit_body(body);
10831083

10841084
// Add formal parameters.
1085+
let mut uninhabited_args = vec![];
10851086
for (arg_ty, arg) in fn_sig.inputs().iter().zip(&body.arguments) {
10861087
// Check the pattern.
10871088
fcx.check_pat_walk(&arg.pat, arg_ty,
10881089
ty::BindingMode::BindByValue(hir::Mutability::MutImmutable), true);
10891090

1091+
// If any of a function's parameters have a type that is uninhabited, then it
1092+
// cannot be called (because its arguments cannot be constructed).
1093+
let module = fcx.tcx.hir().get_module_parent(fn_id);
1094+
if fcx.tcx.is_ty_uninhabited_from(module, arg_ty) {
1095+
uninhabited_args.push(arg);
1096+
}
1097+
10901098
// Check that argument is Sized.
10911099
// The check for a non-trivial pattern is a hack to avoid duplicate warnings
10921100
// for simple cases like `fn foo(x: Trait)`,
@@ -1098,6 +1106,28 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
10981106
fcx.write_ty(arg.hir_id, arg_ty);
10991107
}
11001108

1109+
if !uninhabited_args.is_empty() {
1110+
match fcx.tcx.hir().find(fcx.tcx.hir().get_parent(fn_id)) {
1111+
Some(Node::Item(&hir::Item { node: ItemKind::Impl(..), .. })) => {
1112+
// We only want to warn for functions with parameters of uninhabited types if they
1113+
// are not required (e.g. trait implementations). In the future, such
1114+
// implementations may be unnecessary, but for now they are required.
1115+
}
1116+
_ => {
1117+
let mut err = fcx.tcx.struct_span_lint_node(
1118+
lint::builtin::UNREACHABLE_CODE,
1119+
fn_id,
1120+
fcx.tcx.hir().span(fn_id),
1121+
"functions with parameters of uninhabited types are uncallable",
1122+
);
1123+
for arg in uninhabited_args {
1124+
err.span_label(arg.pat.span, format!("this parameter has an uninhabited type"));
1125+
}
1126+
err.emit();
1127+
}
1128+
}
1129+
}
1130+
11011131
let fn_hir_id = fcx.tcx.hir().node_to_hir_id(fn_id);
11021132
inherited.tables.borrow_mut().liberated_fn_sigs_mut().insert(fn_hir_id, fn_sig);
11031133

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#![deny(unreachable_code)]
2+
3+
enum Void {}
4+
5+
fn foo(a: (), b: Void) { //~ ERROR functions with parameters of uninhabited types are uncallable
6+
a
7+
}
8+
9+
trait Foo {
10+
fn foo(a: Self);
11+
}
12+
13+
impl Foo for Void {
14+
fn foo(a: Void) {} // ok
15+
}
16+
17+
fn main() {}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error: functions with parameters of uninhabited types are uncallable
2+
--> $DIR/uninhabited-function-parameter-warning.rs:5:1
3+
|
4+
LL | fn foo(a: (), b: Void) { //~ ERROR functions with parameters of uninhabited types are uncallable
5+
| ^ - this parameter has an uninhabited type
6+
| _|
7+
| |
8+
LL | | a
9+
LL | | }
10+
| |_^
11+
|
12+
note: lint level defined here
13+
--> $DIR/uninhabited-function-parameter-warning.rs:1:9
14+
|
15+
LL | #![deny(unreachable_code)]
16+
| ^^^^^^^^^^^^^^^^
17+
18+
error: aborting due to previous error
19+

0 commit comments

Comments
 (0)