From 7ee8e7a9b846686148b8797ecc5ae724a6c5a1a9 Mon Sep 17 00:00:00 2001 From: Nathaniel Hamovitz <18648574+nhamovitz@users.noreply.github.com> Date: Fri, 15 Oct 2021 16:16:27 -0700 Subject: [PATCH] Implement detecting trailing zero-sized array --- clippy_lints/src/lib.rs | 4 +- ...railing_zero_sized_array_without_repr_c.rs | 62 ++++++++++++------- ...railing_zero_sized_array_without_repr_c.rs | 26 ++++++++ 3 files changed, 69 insertions(+), 23 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 6624ee931..d494892c3 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -30,7 +30,6 @@ extern crate rustc_index; extern crate rustc_infer; extern crate rustc_lexer; extern crate rustc_lint; -extern crate rustc_lint_defs; extern crate rustc_middle; extern crate rustc_mir_dataflow; extern crate rustc_parse; @@ -488,7 +487,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(utils::internal_lints::OuterExpnDataPass)); } - store.register_early_pass(|| Box::new(trailing_zero_sized_array_without_repr_c::TrailingZeroSizedArrayWithoutReprC)); store.register_late_pass(|| Box::new(utils::author::Author)); store.register_late_pass(|| Box::new(await_holding_invalid::AwaitHolding)); store.register_late_pass(|| Box::new(serde_api::SerdeApi)); @@ -780,6 +778,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default())); store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch)); store.register_late_pass(move || Box::new(format_args::FormatArgs)); + store.register_late_pass(|| Box::new(trailing_zero_sized_array_without_repr_c::TrailingZeroSizedArrayWithoutReprC)); + } #[rustfmt::skip] diff --git a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs index a96b87922..6ca382d16 100644 --- a/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs +++ b/clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs @@ -1,6 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_lint_defs::Applicability; +// use clippy_utils::is_integer_const; +use clippy_utils::consts::{miri_to_const, Constant}; +use rustc_errors::Applicability; +use rustc_hir::{Item, ItemKind, TyKind, VariantData}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -36,38 +39,55 @@ declare_lint_pass!(TrailingZeroSizedArrayWithoutReprC => [TRAILING_ZERO_SIZED_AR // TODO: Register the lint pass in `clippy_lints/src/lib.rs`, // e.g. store.register_early_pass(|| // Box::new(trailing_zero_sized_array_without_repr_c::TrailingZeroSizedArrayWithoutReprC)); +// DONE! -impl EarlyLintPass for TrailingZeroSizedArrayWithoutReprC { - fn check_struct_def(&mut self, cx: &EarlyContext<'_>, data: &rustc_ast::VariantData) { - if is_struct_with_trailing_zero_sized_array(cx, data) && !has_repr_c(cx, data) { - span_lint_and_sugg( - cx, - todo!(), - todo!(), - todo!(), - "try", - "`#[repr(C)]`".to_string(), - Applicability::MachineApplicable, - ) +impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutReprC { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if is_struct_with_trailing_zero_sized_array(cx, item) + /* && !has_repr_c(cx, item) */ + { + // span_lint_and_sugg( + // cx, + // todo!(), + // todo!(), + // todo!(), + // "try", + // "`#[repr(C)]`".to_string(), + // Applicability::MachineApplicable, + // ); + // println!("consider yourself linted 😎"); } } } -fn is_struct_with_trailing_zero_sized_array(cx: &EarlyContext<'_>, data: &rustc_ast::VariantData) -> bool { +fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool { + dbg!(item.ident); if_chain! { - if let rustc_ast::ast::VariantData::Struct(field_defs, some_bool_huh) = data; + if let ItemKind::Struct(data, _generics) = &item.kind; + if let VariantData::Struct(field_defs, _) = data; if let Some(last_field) = field_defs.last(); - if let rustc_ast::ast::TyKind::Array(_, aconst) = &last_field.ty.kind; - // TODO: if array is zero-sized; + if let TyKind::Array(_, aconst) = last_field.ty.kind; + let aconst_def_id = cx.tcx.hir().body_owner_def_id(aconst.body).to_def_id(); + let ty = cx.tcx.type_of(aconst_def_id); + let constant = cx + .tcx + .const_eval_poly(aconst_def_id) // NOTE: maybe const_eval_resolve? seems especially cursed to be using a const expr which resolves to 0 to create a zero-sized array, tho + .ok() + .map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty)); + if let Some(Constant::Int(val)) = constant.and_then(miri_to_const); + if val == 0; then { - dbg!(aconst); + eprintln!("true"); true } else { + // dbg!(aconst); + eprintln!("false"); false } } } -fn has_repr_c(cx: &EarlyContext<'_>, data: &rustc_ast::VariantData) -> bool { - todo!() +fn has_repr_c(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool { + // todo!() + true } diff --git a/tests/ui/trailing_zero_sized_array_without_repr_c.rs b/tests/ui/trailing_zero_sized_array_without_repr_c.rs index 771622178..5f844f16b 100644 --- a/tests/ui/trailing_zero_sized_array_without_repr_c.rs +++ b/tests/ui/trailing_zero_sized_array_without_repr_c.rs @@ -20,4 +20,30 @@ struct GenericArrayType { last: [T; 0], } +struct SizedArray { + field: i32, + last: [usize; 1], +} + +const ZERO: usize = 0; +struct ZeroSizedFromExternalConst { + field: i32, + last: [usize; ZERO], +} + +const ONE: usize = 1; +struct NonZeroSizedFromExternalConst { + field: i32, + last: [usize; ONE], +} + +#[allow(clippy::eq_op)] // lmao im impressed +const fn compute_zero() -> usize { + (4 + 6) - (2 * 5) +} +struct UsingFunction { + field: i32, + last: [usize; compute_zero()], +} + fn main() {}