Skip to content

Commit 9b3f55e

Browse files
committed
tried to simplify but it doesn't work :/
1 parent 5fdf934 commit 9b3f55e

File tree

2 files changed

+61
-82
lines changed

2 files changed

+61
-82
lines changed

clippy_lints/src/trailing_zero_sized_array_without_repr_c.rs

Lines changed: 34 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
use clippy_utils::consts::{miri_to_const, Constant};
22
use clippy_utils::diagnostics::span_lint_and_help;
33
use rustc_ast::Attribute;
4-
use rustc_hir::def_id::LocalDefId;
54
use rustc_hir::{Item, ItemKind, VariantData};
65
use rustc_lint::{LateContext, LateLintPass};
76
use rustc_middle::dep_graph::DepContext;
8-
use rustc_middle::ty as ty_mod;
9-
use rustc_middle::ty::ReprFlags;
7+
use rustc_middle::ty::Const;
108
use rustc_session::{declare_lint_pass, declare_tool_lint};
11-
use rustc_span::sym;
129

1310
declare_clippy_lint! {
1411
/// ### What it does
@@ -43,93 +40,55 @@ declare_lint_pass!(TrailingZeroSizedArrayWithoutReprC => [TRAILING_ZERO_SIZED_AR
4340

4441
impl<'tcx> LateLintPass<'tcx> for TrailingZeroSizedArrayWithoutReprC {
4542
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
46-
dbg!(item.ident);
47-
if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item.def_id) {
48-
// span_lint_and_help(
49-
// cx,
50-
// TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C,
51-
// item.span,
52-
// "trailing zero-sized array in a struct which is not marked `#[repr(C)]`",
53-
// None,
54-
// "consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute)",
55-
// );
56-
eprintln!("— consider yourself linted — 🦀")
43+
if is_struct_with_trailing_zero_sized_array(cx, item) {
44+
let attrs = cx.tcx.get_attrs(item.def_id.to_def_id());
45+
let first_attr = attrs.first(); // Actually, I've no idea if this is guaranteed to be the first one in the source code.
46+
47+
let lint_span = if let Some(first_attr) = first_attr {
48+
first_attr.span.until(item.span)
49+
} else {
50+
item.span
51+
};
52+
53+
if !has_repr_attr(cx, attrs) {
54+
span_lint_and_help(
55+
cx,
56+
TRAILING_ZERO_SIZED_ARRAY_WITHOUT_REPR_C,
57+
lint_span,
58+
"trailing zero-sized array in a struct which is not marked `#[repr(C)]`",
59+
None,
60+
"consider annotating the struct definition with `#[repr(C)]` (or another `repr` attribute)",
61+
);
62+
}
5763
}
5864
}
5965
}
6066

6167
fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool {
6268
if_chain! {
63-
if let ItemKind::Struct(data, _generics) = &item.kind;
69+
// Check if last field is an array
70+
if let ItemKind::Struct(data, _) = &item.kind;
6471
if let VariantData::Struct(field_defs, _) = data;
6572
if let Some(last_field) = field_defs.last();
66-
if let rustc_hir::TyKind::Array(_, aconst) = last_field.ty.kind;
67-
let aconst_def_id = cx.tcx.hir().body_owner_def_id(aconst.body).to_def_id();
68-
let ty = cx.tcx.type_of(aconst_def_id);
69-
let constant = cx
70-
.tcx
71-
// NOTE: maybe const_eval_resolve?
72-
.const_eval_poly(aconst_def_id)
73-
.ok()
74-
.map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty));
75-
if let Some(Constant::Int(val)) = constant.and_then(miri_to_const);
76-
if val == 0;
77-
then {
78-
true
79-
} else {
80-
false
81-
}
82-
}
83-
}
84-
85-
fn has_repr_attr(cx: &LateContext<'tcx>, def_id: LocalDefId) -> bool {
86-
let attrs_get_attrs = get_attrs_get_attrs(cx, def_id);
87-
let attrs_hir_map = get_attrs_hir_map(cx, def_id);
73+
if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind;
8874

89-
let b11 = includes_repr_attr_using_sym(attrs_get_attrs);
90-
let b12 = includes_repr_attr_using_sym(attrs_hir_map);
91-
let b21 = includes_repr_attr_using_helper(cx, attrs_get_attrs);
92-
let b22 = includes_repr_attr_using_helper(cx, attrs_hir_map);
93-
let b3 = has_repr_attr_using_adt(cx, def_id);
94-
let all_same = (b11 && b12 && b21 && b22 && b3) || (!b11 && !b12 && !b21 && !b22 && !b3);
95-
dbg!(all_same);
75+
// Check if that that array zero-sized.
76+
let length_ldid = cx.tcx.hir().local_def_id(length.hir_id);
77+
let length = Const::from_anon_const(cx.tcx, length_ldid);
78+
if let Some(Constant::Int(length)) = miri_to_const(length);
79+
if length == 0;
9680

97-
b21
98-
}
99-
100-
fn get_attrs_get_attrs(cx: &LateContext<'tcx>, def_id: LocalDefId) -> &'tcx [Attribute] {
101-
cx.tcx.get_attrs(def_id.to_def_id())
102-
}
103-
104-
fn get_attrs_hir_map(cx: &LateContext<'tcx>, def_id: LocalDefId) -> &'tcx [Attribute] {
105-
let hir_map = cx.tcx.hir();
106-
let hir_id = hir_map.local_def_id_to_hir_id(def_id);
107-
hir_map.attrs(hir_id)
108-
}
109-
110-
// Don't like this because it's so dependent on the current list of `repr` flags and it would have
111-
// to be manually updated if that ever expanded. idk if there's any mechanism in `bitflag!` or
112-
// elsewhere for requiring that sort of exhaustiveness
113-
fn has_repr_attr_using_adt(cx: &LateContext<'tcx>, def_id: LocalDefId) -> bool {
114-
let ty = cx.tcx.type_of(def_id.to_def_id());
115-
if let ty_mod::Adt(adt, _) = ty.kind() {
116-
if adt.is_struct() {
117-
let repr = adt.repr;
118-
let repr_attr = ReprFlags::IS_C | ReprFlags::IS_TRANSPARENT | ReprFlags::IS_SIMD | ReprFlags::IS_LINEAR;
119-
repr.int.is_some() || repr.align.is_some() || repr.pack.is_some() || repr.flags.intersects(repr_attr)
81+
then {
82+
true
12083
} else {
12184
false
12285
}
123-
} else {
124-
false
12586
}
12687
}
12788

128-
fn includes_repr_attr_using_sym(attrs: &'tcx [Attribute]) -> bool {
129-
attrs.iter().any(|attr| attr.has_name(sym::repr))
130-
}
131-
132-
fn includes_repr_attr_using_helper(cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) -> bool {
89+
fn has_repr_attr(cx: &LateContext<'tcx>, attrs: &[Attribute]) -> bool {
90+
// NOTE: there's at least four other ways to do this but I liked this one the best. (All five agreed
91+
// on all testcases.) Happy to use another; they're in the commit history.
13392
attrs
13493
.iter()
13594
.any(|attr| !rustc_attr::find_repr_attrs(cx.tcx.sess(), attr).is_empty())

tests/ui/trailing_zero_sized_array_without_repr_c.rs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ struct RarelyUseful {
88
last: [usize; 0],
99
}
1010

11-
struct OnlyFieldIsZeroSizeArray {
11+
struct OnlyField {
1212
first_and_last: [usize; 0],
1313
}
1414

@@ -18,19 +18,19 @@ struct GenericArrayType<T> {
1818
}
1919

2020
#[derive(Debug)]
21-
struct PlayNiceWithOtherAttributesDerive {
21+
struct OnlyAnotherAttributeDerive {
2222
field: i32,
2323
last: [usize; 0],
2424
}
2525

2626
#[must_use]
27-
struct PlayNiceWithOtherAttributesMustUse {
27+
struct OnlyAnotherAttributeMustUse {
2828
field: i32,
2929
last: [usize; 0],
3030
}
3131

3232
const ZERO: usize = 0;
33-
struct ZeroSizedFromExternalConst {
33+
struct ZeroSizedWithConst {
3434
field: i32,
3535
last: [usize; ZERO],
3636
}
@@ -39,7 +39,7 @@ struct ZeroSizedFromExternalConst {
3939
const fn compute_zero() -> usize {
4040
(4 + 6) - (2 * 5)
4141
}
42-
struct UsingFunction {
42+
struct ZeroSizedWithConstFunction {
4343
field: i32,
4444
last: [usize; compute_zero()],
4545
}
@@ -72,17 +72,36 @@ struct GoodReason {
7272
last: [usize; 0],
7373
}
7474

75+
#[repr(C)]
76+
struct OnlyFieldWithReprC {
77+
first_and_last: [usize; 0],
78+
}
79+
7580
struct NonZeroSizedArray {
7681
field: i32,
7782
last: [usize; 1],
7883
}
7984

8085
const ONE: usize = 1;
81-
struct NonZeroSizedFromExternalConst {
86+
struct NonZeroSizedWithConst {
8287
field: i32,
8388
last: [usize; ONE],
8489
}
8590

91+
#[derive(Debug)]
92+
#[repr(C)]
93+
struct OtherAttributesDerive {
94+
field: i32,
95+
last: [usize; 0],
96+
}
97+
98+
#[must_use]
99+
#[repr(C)]
100+
struct OtherAttributesMustUse {
101+
field: i32,
102+
last: [usize; 0],
103+
}
104+
86105
#[repr(packed)]
87106
struct ReprPacked {
88107
field: i32,
@@ -129,5 +148,6 @@ enum DontLintAnonymousStructsFromDesuraging {
129148
// }
130149

131150
fn main() {
132-
let _ = PlayNiceWithOtherAttributesMustUse { field: 0, last: [] };
151+
let _ = OnlyAnotherAttributeMustUse { field: 0, last: [] };
152+
let _ = OtherAttributesMustUse { field: 0, last: [] };
133153
}

0 commit comments

Comments
 (0)