Skip to content

Commit cdfa38a

Browse files
committed
new lint: uninhabited_reference
1 parent ee83760 commit cdfa38a

8 files changed

+151
-2
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5583,6 +5583,7 @@ Released 2018-09-13
55835583
[`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops
55845584
[`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
55855585
[`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented
5586+
[`uninhabited_references`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninhabited_references
55865587
[`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init
55875588
[`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec
55885589
[`uninlined_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args

clippy_lints/src/declared_lints.rs

+1
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
679679
crate::unicode::INVISIBLE_CHARACTERS_INFO,
680680
crate::unicode::NON_ASCII_LITERAL_INFO,
681681
crate::unicode::UNICODE_NOT_NFC_INFO,
682+
crate::uninhabited_references::UNINHABITED_REFERENCES_INFO,
682683
crate::uninit_vec::UNINIT_VEC_INFO,
683684
crate::unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD_INFO,
684685
crate::unit_types::LET_UNIT_VALUE_INFO,

clippy_lints/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ mod tuple_array_conversions;
326326
mod types;
327327
mod undocumented_unsafe_blocks;
328328
mod unicode;
329+
mod uninhabited_references;
329330
mod uninit_vec;
330331
mod unit_return_expecting_ord;
331332
mod unit_types;
@@ -1071,6 +1072,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
10711072
store.register_late_pass(|_| Box::new(iter_over_hash_type::IterOverHashType));
10721073
store.register_late_pass(|_| Box::new(impl_hash_with_borrow_str_and_bytes::ImplHashWithBorrowStrBytes));
10731074
store.register_late_pass(|_| Box::new(repeat_vec_with_capacity::RepeatVecWithCapacity));
1075+
store.register_late_pass(|_| Box::new(uninhabited_references::UninhabitedReferences));
10741076
// add lints here, do not remove this comment, it's used in `new_lint`
10751077
}
10761078

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
use clippy_utils::diagnostics::span_lint;
2+
use rustc_hir::intravisit::FnKind;
3+
use rustc_hir::{Body, Expr, ExprKind, FnDecl, FnRetTy, TyKind, UnOp};
4+
use rustc_hir_analysis::hir_ty_to_ty;
5+
use rustc_lint::{LateContext, LateLintPass};
6+
use rustc_middle::lint::in_external_macro;
7+
use rustc_session::declare_lint_pass;
8+
use rustc_span::def_id::LocalDefId;
9+
use rustc_span::Span;
10+
11+
declare_clippy_lint! {
12+
/// ### What it does
13+
/// It detects references to uninhabited types, such as `!` and
14+
/// warns when those are either dereferenced or returned from a function.
15+
///
16+
/// ### Why is this bad?
17+
/// Dereferencing a reference to an uninhabited type would create
18+
/// an instance of such a type, which cannot exist. This constitutes
19+
/// undefined behaviour. Such a reference could have been created
20+
/// by `unsafe` code.
21+
///
22+
/// ### Example
23+
/// The following function can return a reference to an uninhabited type
24+
/// (`Infallible`) because it uses `unsafe` code to create it. However,
25+
/// the user of such a function could dereference the return value and
26+
/// trigger an undefined behavior from safe code.
27+
///
28+
/// ```no_run
29+
/// fn create_ref() -> &'static std::convert::Infallible {
30+
/// unsafe { std::mem::transmute(&()) }
31+
/// }
32+
/// ```
33+
#[clippy::version = "1.76.0"]
34+
pub UNINHABITED_REFERENCES,
35+
suspicious,
36+
"reference to uninhabited type"
37+
}
38+
39+
declare_lint_pass!(UninhabitedReferences => [UNINHABITED_REFERENCES]);
40+
41+
impl LateLintPass<'_> for UninhabitedReferences {
42+
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
43+
if in_external_macro(cx.tcx.sess, expr.span) {
44+
return;
45+
}
46+
47+
if let ExprKind::Unary(UnOp::Deref, _) = expr.kind {
48+
let ty = cx.typeck_results().expr_ty_adjusted(expr);
49+
if ty.is_privately_uninhabited(cx.tcx, cx.param_env) {
50+
span_lint(
51+
cx,
52+
UNINHABITED_REFERENCES,
53+
expr.span,
54+
"dereferencing a reference to an uninhabited type is undefined behavior",
55+
);
56+
}
57+
}
58+
}
59+
60+
fn check_fn(
61+
&mut self,
62+
cx: &LateContext<'_>,
63+
kind: FnKind<'_>,
64+
fndecl: &'_ FnDecl<'_>,
65+
_: &'_ Body<'_>,
66+
span: Span,
67+
_: LocalDefId,
68+
) {
69+
if in_external_macro(cx.tcx.sess, span) || matches!(kind, FnKind::Closure) {
70+
return;
71+
}
72+
if let FnRetTy::Return(hir_ty) = fndecl.output
73+
&& let TyKind::Ref(_, mut_ty) = hir_ty.kind
74+
&& hir_ty_to_ty(cx.tcx, mut_ty.ty).is_privately_uninhabited(cx.tcx, cx.param_env)
75+
{
76+
span_lint(
77+
cx,
78+
UNINHABITED_REFERENCES,
79+
hir_ty.span,
80+
"dereferencing a reference to an uninhabited type would be undefined behavior",
81+
);
82+
}
83+
}
84+
}

tests/ui/infallible_destructuring_match.fixed

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![feature(exhaustive_patterns, never_type)]
22
#![allow(dead_code, unreachable_code, unused_variables)]
3-
#![allow(clippy::let_and_return)]
3+
#![allow(clippy::let_and_return, clippy::uninhabited_references)]
44

55
enum SingleVariantEnum {
66
Variant(i32),

tests/ui/infallible_destructuring_match.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![feature(exhaustive_patterns, never_type)]
22
#![allow(dead_code, unreachable_code, unused_variables)]
3-
#![allow(clippy::let_and_return)]
3+
#![allow(clippy::let_and_return, clippy::uninhabited_references)]
44

55
enum SingleVariantEnum {
66
Variant(i32),

tests/ui/uninhabited_references.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#![warn(clippy::uninhabited_references)]
2+
#![feature(never_type)]
3+
4+
fn ret_uninh_ref() -> &'static std::convert::Infallible {
5+
unsafe { std::mem::transmute(&()) }
6+
}
7+
8+
macro_rules! ret_something {
9+
($name:ident, $ty:ty) => {
10+
fn $name(x: &$ty) -> &$ty {
11+
&*x
12+
}
13+
};
14+
}
15+
16+
ret_something!(id_u32, u32);
17+
ret_something!(id_never, !);
18+
19+
fn main() {
20+
let x = ret_uninh_ref();
21+
let _ = *x;
22+
}
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
error: dereferencing a reference to an uninhabited type would be undefined behavior
2+
--> $DIR/uninhabited_references.rs:4:23
3+
|
4+
LL | fn ret_uninh_ref() -> &'static std::convert::Infallible {
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::uninhabited-references` implied by `-D warnings`
8+
= help: to override `-D warnings` add `#[allow(clippy::uninhabited_references)]`
9+
10+
error: dereferencing a reference to an uninhabited type would be undefined behavior
11+
--> $DIR/uninhabited_references.rs:10:30
12+
|
13+
LL | fn $name(x: &$ty) -> &$ty {
14+
| ^^^^
15+
...
16+
LL | ret_something!(id_never, !);
17+
| --------------------------- in this macro invocation
18+
|
19+
= note: this error originates in the macro `ret_something` (in Nightly builds, run with -Z macro-backtrace for more info)
20+
21+
error: dereferencing a reference to an uninhabited type is undefined behavior
22+
--> $DIR/uninhabited_references.rs:11:14
23+
|
24+
LL | &*x
25+
| ^^
26+
...
27+
LL | ret_something!(id_never, !);
28+
| --------------------------- in this macro invocation
29+
|
30+
= note: this error originates in the macro `ret_something` (in Nightly builds, run with -Z macro-backtrace for more info)
31+
32+
error: dereferencing a reference to an uninhabited type is undefined behavior
33+
--> $DIR/uninhabited_references.rs:21:13
34+
|
35+
LL | let _ = *x;
36+
| ^^
37+
38+
error: aborting due to 4 previous errors
39+

0 commit comments

Comments
 (0)