Skip to content

Commit 7ee8e7a

Browse files
committed
Implement detecting trailing zero-sized array
1 parent 92d3b77 commit 7ee8e7a

File tree

3 files changed

+69
-23
lines changed

3 files changed

+69
-23
lines changed

clippy_lints/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ extern crate rustc_index;
3030
extern crate rustc_infer;
3131
extern crate rustc_lexer;
3232
extern crate rustc_lint;
33-
extern crate rustc_lint_defs;
3433
extern crate rustc_middle;
3534
extern crate rustc_mir_dataflow;
3635
extern crate rustc_parse;
@@ -488,7 +487,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
488487
store.register_late_pass(|| Box::new(utils::internal_lints::OuterExpnDataPass));
489488
}
490489

491-
store.register_early_pass(|| Box::new(trailing_zero_sized_array_without_repr_c::TrailingZeroSizedArrayWithoutReprC));
492490
store.register_late_pass(|| Box::new(utils::author::Author));
493491
store.register_late_pass(|| Box::new(await_holding_invalid::AwaitHolding));
494492
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:
780778
store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default()));
781779
store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch));
782780
store.register_late_pass(move || Box::new(format_args::FormatArgs));
781+
store.register_late_pass(|| Box::new(trailing_zero_sized_array_without_repr_c::TrailingZeroSizedArrayWithoutReprC));
782+
783783
}
784784

785785
#[rustfmt::skip]

clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use rustc_lint::{EarlyContext, EarlyLintPass};
3-
use rustc_lint_defs::Applicability;
2+
// use clippy_utils::is_integer_const;
3+
use clippy_utils::consts::{miri_to_const, Constant};
4+
use rustc_errors::Applicability;
5+
use rustc_hir::{Item, ItemKind, TyKind, VariantData};
6+
use rustc_lint::{LateContext, LateLintPass};
47
use rustc_session::{declare_lint_pass, declare_tool_lint};
58

69
declare_clippy_lint! {
@@ -36,38 +39,55 @@ declare_lint_pass!(TrailingZeroSizedArrayWithoutReprC => [TRAILING_ZERO_SIZED_AR
3639
// TODO: Register the lint pass in `clippy_lints/src/lib.rs`,
3740
// e.g. store.register_early_pass(||
3841
// Box::new(trailing_zero_sized_array_without_repr_c::TrailingZeroSizedArrayWithoutReprC));
42+
// DONE!
3943

40-
impl EarlyLintPass for TrailingZeroSizedArrayWithoutReprC {
41-
fn check_struct_def(&mut self, cx: &EarlyContext<'_>, data: &rustc_ast::VariantData) {
42-
if is_struct_with_trailing_zero_sized_array(cx, data) && !has_repr_c(cx, data) {
43-
span_lint_and_sugg(
44-
cx,
45-
todo!(),
46-
todo!(),
47-
todo!(),
48-
"try",
49-
"`#[repr(C)]`".to_string(),
50-
Applicability::MachineApplicable,
51-
)
44+
impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutReprC {
45+
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
46+
if is_struct_with_trailing_zero_sized_array(cx, item)
47+
/* && !has_repr_c(cx, item) */
48+
{
49+
// span_lint_and_sugg(
50+
// cx,
51+
// todo!(),
52+
// todo!(),
53+
// todo!(),
54+
// "try",
55+
// "`#[repr(C)]`".to_string(),
56+
// Applicability::MachineApplicable,
57+
// );
58+
// println!("consider yourself linted 😎");
5259
}
5360
}
5461
}
5562

56-
fn is_struct_with_trailing_zero_sized_array(cx: &EarlyContext<'_>, data: &rustc_ast::VariantData) -> bool {
63+
fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool {
64+
dbg!(item.ident);
5765
if_chain! {
58-
if let rustc_ast::ast::VariantData::Struct(field_defs, some_bool_huh) = data;
66+
if let ItemKind::Struct(data, _generics) = &item.kind;
67+
if let VariantData::Struct(field_defs, _) = data;
5968
if let Some(last_field) = field_defs.last();
60-
if let rustc_ast::ast::TyKind::Array(_, aconst) = &last_field.ty.kind;
61-
// TODO: if array is zero-sized;
69+
if let TyKind::Array(_, aconst) = last_field.ty.kind;
70+
let aconst_def_id = cx.tcx.hir().body_owner_def_id(aconst.body).to_def_id();
71+
let ty = cx.tcx.type_of(aconst_def_id);
72+
let constant = cx
73+
.tcx
74+
.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
75+
.ok()
76+
.map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty));
77+
if let Some(Constant::Int(val)) = constant.and_then(miri_to_const);
78+
if val == 0;
6279
then {
63-
dbg!(aconst);
80+
eprintln!("true");
6481
true
6582
} else {
83+
// dbg!(aconst);
84+
eprintln!("false");
6685
false
6786
}
6887
}
6988
}
7089

71-
fn has_repr_c(cx: &EarlyContext<'_>, data: &rustc_ast::VariantData) -> bool {
72-
todo!()
90+
fn has_repr_c(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool {
91+
// todo!()
92+
true
7393
}

tests/ui/trailing_zero_sized_array_without_repr_c.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,30 @@ struct GenericArrayType<T> {
2020
last: [T; 0],
2121
}
2222

23+
struct SizedArray {
24+
field: i32,
25+
last: [usize; 1],
26+
}
27+
28+
const ZERO: usize = 0;
29+
struct ZeroSizedFromExternalConst {
30+
field: i32,
31+
last: [usize; ZERO],
32+
}
33+
34+
const ONE: usize = 1;
35+
struct NonZeroSizedFromExternalConst {
36+
field: i32,
37+
last: [usize; ONE],
38+
}
39+
40+
#[allow(clippy::eq_op)] // lmao im impressed
41+
const fn compute_zero() -> usize {
42+
(4 + 6) - (2 * 5)
43+
}
44+
struct UsingFunction {
45+
field: i32,
46+
last: [usize; compute_zero()],
47+
}
48+
2349
fn main() {}

0 commit comments

Comments
 (0)