new lint: uninhabited_reference
This commit is contained in:
parent
ee8376075d
commit
cdfa38a9d1
@ -5583,6 +5583,7 @@ Released 2018-09-13
|
|||||||
[`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops
|
[`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops
|
||||||
[`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
|
[`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
|
||||||
[`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented
|
[`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented
|
||||||
|
[`uninhabited_references`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninhabited_references
|
||||||
[`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init
|
[`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init
|
||||||
[`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec
|
[`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec
|
||||||
[`uninlined_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
|
[`uninlined_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
|
||||||
|
@ -679,6 +679,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||||||
crate::unicode::INVISIBLE_CHARACTERS_INFO,
|
crate::unicode::INVISIBLE_CHARACTERS_INFO,
|
||||||
crate::unicode::NON_ASCII_LITERAL_INFO,
|
crate::unicode::NON_ASCII_LITERAL_INFO,
|
||||||
crate::unicode::UNICODE_NOT_NFC_INFO,
|
crate::unicode::UNICODE_NOT_NFC_INFO,
|
||||||
|
crate::uninhabited_references::UNINHABITED_REFERENCES_INFO,
|
||||||
crate::uninit_vec::UNINIT_VEC_INFO,
|
crate::uninit_vec::UNINIT_VEC_INFO,
|
||||||
crate::unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD_INFO,
|
crate::unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD_INFO,
|
||||||
crate::unit_types::LET_UNIT_VALUE_INFO,
|
crate::unit_types::LET_UNIT_VALUE_INFO,
|
||||||
|
@ -326,6 +326,7 @@ mod tuple_array_conversions;
|
|||||||
mod types;
|
mod types;
|
||||||
mod undocumented_unsafe_blocks;
|
mod undocumented_unsafe_blocks;
|
||||||
mod unicode;
|
mod unicode;
|
||||||
|
mod uninhabited_references;
|
||||||
mod uninit_vec;
|
mod uninit_vec;
|
||||||
mod unit_return_expecting_ord;
|
mod unit_return_expecting_ord;
|
||||||
mod unit_types;
|
mod unit_types;
|
||||||
@ -1071,6 +1072,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||||||
store.register_late_pass(|_| Box::new(iter_over_hash_type::IterOverHashType));
|
store.register_late_pass(|_| Box::new(iter_over_hash_type::IterOverHashType));
|
||||||
store.register_late_pass(|_| Box::new(impl_hash_with_borrow_str_and_bytes::ImplHashWithBorrowStrBytes));
|
store.register_late_pass(|_| Box::new(impl_hash_with_borrow_str_and_bytes::ImplHashWithBorrowStrBytes));
|
||||||
store.register_late_pass(|_| Box::new(repeat_vec_with_capacity::RepeatVecWithCapacity));
|
store.register_late_pass(|_| Box::new(repeat_vec_with_capacity::RepeatVecWithCapacity));
|
||||||
|
store.register_late_pass(|_| Box::new(uninhabited_references::UninhabitedReferences));
|
||||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
84
clippy_lints/src/uninhabited_references.rs
Normal file
84
clippy_lints/src/uninhabited_references.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
use clippy_utils::diagnostics::span_lint;
|
||||||
|
use rustc_hir::intravisit::FnKind;
|
||||||
|
use rustc_hir::{Body, Expr, ExprKind, FnDecl, FnRetTy, TyKind, UnOp};
|
||||||
|
use rustc_hir_analysis::hir_ty_to_ty;
|
||||||
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
|
use rustc_middle::lint::in_external_macro;
|
||||||
|
use rustc_session::declare_lint_pass;
|
||||||
|
use rustc_span::def_id::LocalDefId;
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// It detects references to uninhabited types, such as `!` and
|
||||||
|
/// warns when those are either dereferenced or returned from a function.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// Dereferencing a reference to an uninhabited type would create
|
||||||
|
/// an instance of such a type, which cannot exist. This constitutes
|
||||||
|
/// undefined behaviour. Such a reference could have been created
|
||||||
|
/// by `unsafe` code.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// The following function can return a reference to an uninhabited type
|
||||||
|
/// (`Infallible`) because it uses `unsafe` code to create it. However,
|
||||||
|
/// the user of such a function could dereference the return value and
|
||||||
|
/// trigger an undefined behavior from safe code.
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// fn create_ref() -> &'static std::convert::Infallible {
|
||||||
|
/// unsafe { std::mem::transmute(&()) }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.76.0"]
|
||||||
|
pub UNINHABITED_REFERENCES,
|
||||||
|
suspicious,
|
||||||
|
"reference to uninhabited type"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(UninhabitedReferences => [UNINHABITED_REFERENCES]);
|
||||||
|
|
||||||
|
impl LateLintPass<'_> for UninhabitedReferences {
|
||||||
|
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
|
||||||
|
if in_external_macro(cx.tcx.sess, expr.span) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let ExprKind::Unary(UnOp::Deref, _) = expr.kind {
|
||||||
|
let ty = cx.typeck_results().expr_ty_adjusted(expr);
|
||||||
|
if ty.is_privately_uninhabited(cx.tcx, cx.param_env) {
|
||||||
|
span_lint(
|
||||||
|
cx,
|
||||||
|
UNINHABITED_REFERENCES,
|
||||||
|
expr.span,
|
||||||
|
"dereferencing a reference to an uninhabited type is undefined behavior",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_fn(
|
||||||
|
&mut self,
|
||||||
|
cx: &LateContext<'_>,
|
||||||
|
kind: FnKind<'_>,
|
||||||
|
fndecl: &'_ FnDecl<'_>,
|
||||||
|
_: &'_ Body<'_>,
|
||||||
|
span: Span,
|
||||||
|
_: LocalDefId,
|
||||||
|
) {
|
||||||
|
if in_external_macro(cx.tcx.sess, span) || matches!(kind, FnKind::Closure) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if let FnRetTy::Return(hir_ty) = fndecl.output
|
||||||
|
&& let TyKind::Ref(_, mut_ty) = hir_ty.kind
|
||||||
|
&& hir_ty_to_ty(cx.tcx, mut_ty.ty).is_privately_uninhabited(cx.tcx, cx.param_env)
|
||||||
|
{
|
||||||
|
span_lint(
|
||||||
|
cx,
|
||||||
|
UNINHABITED_REFERENCES,
|
||||||
|
hir_ty.span,
|
||||||
|
"dereferencing a reference to an uninhabited type would be undefined behavior",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
#![feature(exhaustive_patterns, never_type)]
|
#![feature(exhaustive_patterns, never_type)]
|
||||||
#![allow(dead_code, unreachable_code, unused_variables)]
|
#![allow(dead_code, unreachable_code, unused_variables)]
|
||||||
#![allow(clippy::let_and_return)]
|
#![allow(clippy::let_and_return, clippy::uninhabited_references)]
|
||||||
|
|
||||||
enum SingleVariantEnum {
|
enum SingleVariantEnum {
|
||||||
Variant(i32),
|
Variant(i32),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#![feature(exhaustive_patterns, never_type)]
|
#![feature(exhaustive_patterns, never_type)]
|
||||||
#![allow(dead_code, unreachable_code, unused_variables)]
|
#![allow(dead_code, unreachable_code, unused_variables)]
|
||||||
#![allow(clippy::let_and_return)]
|
#![allow(clippy::let_and_return, clippy::uninhabited_references)]
|
||||||
|
|
||||||
enum SingleVariantEnum {
|
enum SingleVariantEnum {
|
||||||
Variant(i32),
|
Variant(i32),
|
||||||
|
22
tests/ui/uninhabited_references.rs
Normal file
22
tests/ui/uninhabited_references.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#![warn(clippy::uninhabited_references)]
|
||||||
|
#![feature(never_type)]
|
||||||
|
|
||||||
|
fn ret_uninh_ref() -> &'static std::convert::Infallible {
|
||||||
|
unsafe { std::mem::transmute(&()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! ret_something {
|
||||||
|
($name:ident, $ty:ty) => {
|
||||||
|
fn $name(x: &$ty) -> &$ty {
|
||||||
|
&*x
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ret_something!(id_u32, u32);
|
||||||
|
ret_something!(id_never, !);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = ret_uninh_ref();
|
||||||
|
let _ = *x;
|
||||||
|
}
|
39
tests/ui/uninhabited_references.stderr
Normal file
39
tests/ui/uninhabited_references.stderr
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
error: dereferencing a reference to an uninhabited type would be undefined behavior
|
||||||
|
--> $DIR/uninhabited_references.rs:4:23
|
||||||
|
|
|
||||||
|
LL | fn ret_uninh_ref() -> &'static std::convert::Infallible {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `-D clippy::uninhabited-references` implied by `-D warnings`
|
||||||
|
= help: to override `-D warnings` add `#[allow(clippy::uninhabited_references)]`
|
||||||
|
|
||||||
|
error: dereferencing a reference to an uninhabited type would be undefined behavior
|
||||||
|
--> $DIR/uninhabited_references.rs:10:30
|
||||||
|
|
|
||||||
|
LL | fn $name(x: &$ty) -> &$ty {
|
||||||
|
| ^^^^
|
||||||
|
...
|
||||||
|
LL | ret_something!(id_never, !);
|
||||||
|
| --------------------------- in this macro invocation
|
||||||
|
|
|
||||||
|
= note: this error originates in the macro `ret_something` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: dereferencing a reference to an uninhabited type is undefined behavior
|
||||||
|
--> $DIR/uninhabited_references.rs:11:14
|
||||||
|
|
|
||||||
|
LL | &*x
|
||||||
|
| ^^
|
||||||
|
...
|
||||||
|
LL | ret_something!(id_never, !);
|
||||||
|
| --------------------------- in this macro invocation
|
||||||
|
|
|
||||||
|
= note: this error originates in the macro `ret_something` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: dereferencing a reference to an uninhabited type is undefined behavior
|
||||||
|
--> $DIR/uninhabited_references.rs:21:13
|
||||||
|
|
|
||||||
|
LL | let _ = *x;
|
||||||
|
| ^^
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user