Skip to content

Commit 5f7716d

Browse files
committed
invalid_value: factor finding dangerous inits into separate function
1 parent bdfd698 commit 5f7716d

File tree

1 file changed

+54
-37
lines changed

1 file changed

+54
-37
lines changed

src/librustc_lint/builtin.rs

Lines changed: 54 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1876,8 +1876,34 @@ declare_lint_pass!(InvalidValue => [INVALID_VALUE]);
18761876
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
18771877
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &hir::Expr) {
18781878

1879-
const ZEROED_PATH: &[Symbol] = &[sym::core, sym::mem, sym::zeroed];
1880-
const UININIT_PATH: &[Symbol] = &[sym::core, sym::mem, sym::uninitialized];
1879+
#[derive(Debug)]
1880+
enum InitKind { Zeroed, Uninit };
1881+
1882+
/// Determine if this expression is a "dangerous initialization".
1883+
fn is_dangerous_init(cx: &LateContext<'_, '_>, expr: &hir::Expr) -> Option<InitKind> {
1884+
const ZEROED_PATH: &[Symbol] = &[sym::core, sym::mem, sym::zeroed];
1885+
const UININIT_PATH: &[Symbol] = &[sym::core, sym::mem, sym::uninitialized];
1886+
1887+
if let hir::ExprKind::Call(ref path_expr, ref _args) = expr.node {
1888+
if let hir::ExprKind::Path(ref qpath) = path_expr.node {
1889+
if let Some(def_id) = cx.tables.qpath_res(qpath, path_expr.hir_id)
1890+
.opt_def_id()
1891+
{
1892+
if cx.match_def_path(def_id, &ZEROED_PATH) {
1893+
return Some(InitKind::Zeroed);
1894+
}
1895+
if cx.match_def_path(def_id, &UININIT_PATH) {
1896+
return Some(InitKind::Uninit);
1897+
}
1898+
// FIXME: Also detect `MaybeUninit::zeroed().assume_init()` and
1899+
// `MaybeUninit::uninit().assume_init()`.
1900+
// FIXME: Also detect `transmute` from 0.
1901+
}
1902+
}
1903+
}
1904+
1905+
None
1906+
}
18811907

18821908
/// Information about why a type cannot be initialized this way.
18831909
/// Contains an error message and optionally a span to point at.
@@ -1933,42 +1959,33 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
19331959
}
19341960
}
19351961

1936-
if let hir::ExprKind::Call(ref path_expr, ref _args) = expr.node {
1937-
if let hir::ExprKind::Path(ref qpath) = path_expr.node {
1938-
if let Some(def_id) = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id() {
1939-
if cx.match_def_path(def_id, &ZEROED_PATH) ||
1940-
cx.match_def_path(def_id, &UININIT_PATH)
1941-
{
1942-
// This conjures an instance of a type out of nothing,
1943-
// using zeroed or uninitialized memory.
1944-
// We are extremely conservative with what we warn about.
1945-
let conjured_ty = cx.tables.expr_ty(expr);
1946-
if let Some((msg, span)) = ty_find_init_error(cx.tcx, conjured_ty) {
1947-
let mut err = cx.struct_span_lint(
1948-
INVALID_VALUE,
1949-
expr.span,
1950-
&format!(
1951-
"the type `{}` does not permit {}",
1952-
conjured_ty,
1953-
if cx.match_def_path(def_id, &ZEROED_PATH) {
1954-
"zero-initialization"
1955-
} else {
1956-
"being left uninitialized"
1957-
}
1958-
),
1959-
);
1960-
err.span_label(expr.span,
1961-
"this code causes undefined behavior when executed");
1962-
err.span_label(expr.span, "help: use `MaybeUninit<T>` instead");
1963-
if let Some(span) = span {
1964-
err.span_note(span, &msg);
1965-
} else {
1966-
err.note(&msg);
1967-
}
1968-
err.emit();
1969-
}
1970-
}
1962+
if let Some(init) = is_dangerous_init(cx, expr) {
1963+
// This conjures an instance of a type out of nothing,
1964+
// using zeroed or uninitialized memory.
1965+
// We are extremely conservative with what we warn about.
1966+
let conjured_ty = cx.tables.expr_ty(expr);
1967+
if let Some((msg, span)) = ty_find_init_error(cx.tcx, conjured_ty) {
1968+
let mut err = cx.struct_span_lint(
1969+
INVALID_VALUE,
1970+
expr.span,
1971+
&format!(
1972+
"the type `{}` does not permit {}",
1973+
conjured_ty,
1974+
match init {
1975+
InitKind::Zeroed => "zero-initialization",
1976+
InitKind::Uninit => "being left uninitialized",
1977+
},
1978+
),
1979+
);
1980+
err.span_label(expr.span,
1981+
"this code causes undefined behavior when executed");
1982+
err.span_label(expr.span, "help: use `MaybeUninit<T>` instead");
1983+
if let Some(span) = span {
1984+
err.span_note(span, &msg);
1985+
} else {
1986+
err.note(&msg);
19711987
}
1988+
err.emit();
19721989
}
19731990
}
19741991
}

0 commit comments

Comments
 (0)