});
}
}
+
+declare_lint! {
+ pub INVALID_VALUE,
+ Warn,
+ "an invalid value is being created (such as a NULL reference)"
+}
+
+declare_lint_pass!(InvalidValue => [INVALID_VALUE]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
+ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &hir::Expr) {
+
+ const ZEROED_PATH: &[Symbol] = &[sym::core, sym::mem, sym::zeroed];
+ const UININIT_PATH: &[Symbol] = &[sym::core, sym::mem, sym::uninitialized];
+
+ /// Return `false` only if we are sure this type does *not*
+ /// allow zero initialization.
+ fn ty_maybe_allows_zero_init(ty: Ty<'_>) -> bool {
+ use rustc::ty::TyKind::*;
+ match ty.sty {
+ // Primitive types that don't like 0 as a value.
+ Ref(..) | FnPtr(..) | Never => false,
+ // Conservative fallback.
+ _ => true,
+ }
+ }
+
+ if let hir::ExprKind::Call(ref path_expr, ref _args) = expr.node {
+ if let hir::ExprKind::Path(ref qpath) = path_expr.node {
+ if let Some(def_id) = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id() {
+ if cx.match_def_path(def_id, &ZEROED_PATH) ||
+ cx.match_def_path(def_id, &UININIT_PATH)
+ {
+ // This conjures an instance of a type out of nothing,
+ // using zeroed or uninitialized memory.
+ // We are extremely conservative with what we warn about.
+ let conjured_ty = cx.tables.expr_ty(expr);
+
+ if !ty_maybe_allows_zero_init(conjured_ty) {
+ cx.span_lint(
+ INVALID_VALUE,
+ expr.span,
+ &format!(
+ "the type `{}` does not permit {}",
+ conjured_ty,
+ if cx.match_def_path(def_id, &ZEROED_PATH) {
+ "zero-initialization"
+ } else {
+ "being left uninitialized"
+ }
+ ),
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+}
UnreachablePub: UnreachablePub,
ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
+ InvalidValue: InvalidValue,
]);
)
}
match_beginning_vert,
match_default_bindings,
may_dangle,
+ mem,
member_constraints,
message,
meta,
underscore_imports,
underscore_lifetimes,
uniform_paths,
+ uninitialized,
universal_impl_trait,
unmarked_api,
unreachable_code,
windows,
windows_subsystem,
Yield,
+ zeroed,
}
}
--- /dev/null
+// ignore-tidy-linelength
+// This test checks that calling `mem::{uninitialized,zeroed}` with certain types results
+// in a lint.
+
+#![feature(never_type)]
+#![allow(deprecated)]
+#![deny(invalid_value)]
+
+use std::mem;
+
+fn main() {
+ unsafe {
+ let _val: ! = mem::zeroed(); //~ ERROR: does not permit zero-initialization
+ let _val: ! = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
+
+ let _val: &'static i32 = mem::zeroed(); //~ ERROR: does not permit zero-initialization
+ let _val: &'static i32 = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
+
+ let _val: fn() = mem::zeroed(); //~ ERROR: does not permit zero-initialization
+ let _val: fn() = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
+
+ // Some types that should work just fine.
+ let _val: Option<&'static i32> = mem::zeroed();
+ let _val: Option<fn()> = mem::zeroed();
+ let _val: bool = mem::zeroed();
+ let _val: i32 = mem::zeroed();
+ }
+}
--- /dev/null
+error: the type `!` does not permit zero-initialization
+ --> $DIR/uninitialized-zeroed.rs:15:23
+ |
+LL | let _val: ! = mem::zeroed();
+ | ^^^^^^^^^^^^^
+ |
+note: lint level defined here
+ --> $DIR/uninitialized-zeroed.rs:7:9
+ |
+LL | #![deny(invalid_value)]
+ | ^^^^^^^^^^^^^
+
+error: the type `!` does not permit being left uninitialized
+ --> $DIR/uninitialized-zeroed.rs:16:23
+ |
+LL | let _val: ! = mem::uninitialized();
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: the type `&'static i32` does not permit zero-initialization
+ --> $DIR/uninitialized-zeroed.rs:21:34
+ |
+LL | let _val: &'static i32 = mem::zeroed();
+ | ^^^^^^^^^^^^^
+
+error: the type `&'static i32` does not permit being left uninitialized
+ --> $DIR/uninitialized-zeroed.rs:22:34
+ |
+LL | let _val: &'static i32 = mem::uninitialized();
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: the type `fn()` does not permit zero-initialization
+ --> $DIR/uninitialized-zeroed.rs:24:26
+ |
+LL | let _val: fn() = mem::zeroed();
+ | ^^^^^^^^^^^^^
+
+error: the type `fn()` does not permit being left uninitialized
+ --> $DIR/uninitialized-zeroed.rs:25:26
+ |
+LL | let _val: fn() = mem::uninitialized();
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
// in a runtime panic.
#![feature(never_type)]
-#![allow(deprecated)]
+#![allow(deprecated, invalid_value)]
use std::{mem, panic};