]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
New upstream version 1.72.1+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / trailing_empty_array.rs
CommitLineData
3c0e092e 1use clippy_utils::diagnostics::span_lint_and_help;
487cf647
FG
2use clippy_utils::has_repr_attr;
3use rustc_hir::{Item, ItemKind};
3c0e092e
XL
4use rustc_lint::{LateContext, LateLintPass};
5use rustc_middle::ty::Const;
6use rustc_session::{declare_lint_pass, declare_tool_lint};
3c0e092e
XL
7
8declare_clippy_lint! {
9 /// ### What it does
10 /// Displays a warning when a struct with a trailing zero-sized array is declared without a `repr` attribute.
11 ///
12 /// ### Why is this bad?
5e7ed085 13 /// Zero-sized arrays aren't very useful in Rust itself, so such a struct is likely being created to pass to C code or in some other situation where control over memory layout matters (for example, in conjunction with manual allocation to make it easy to compute the offset of the array). Either way, `#[repr(C)]` (or another `repr` attribute) is needed.
3c0e092e
XL
14 ///
15 /// ### Example
16 /// ```rust
17 /// struct RarelyUseful {
18 /// some_field: u32,
19 /// last: [u32; 0],
20 /// }
21 /// ```
22 ///
23 /// Use instead:
24 /// ```rust
25 /// #[repr(C)]
26 /// struct MoreOftenUseful {
27 /// some_field: usize,
28 /// last: [u32; 0],
29 /// }
30 /// ```
a2a8927a 31 #[clippy::version = "1.58.0"]
3c0e092e
XL
32 pub TRAILING_EMPTY_ARRAY,
33 nursery,
34 "struct with a trailing zero-sized array but without `#[repr(C)]` or another `repr` attribute"
35}
36declare_lint_pass!(TrailingEmptyArray => [TRAILING_EMPTY_ARRAY]);
37
38impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray {
39 fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
40 if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item.hir_id()) {
41 span_lint_and_help(
42 cx,
43 TRAILING_EMPTY_ARRAY,
44 item.span,
45 "trailing zero-sized array in a struct which is not marked with a `repr` attribute",
46 None,
47 &format!(
48 "consider annotating `{}` with `#[repr(C)]` or another `repr` attribute",
49aad941 49 cx.tcx.def_path_str(item.owner_id)
3c0e092e
XL
50 ),
51 );
52 }
53 }
54}
55
5099ac24 56fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
3c0e092e
XL
57 if_chain! {
58 // First check if last field is an array
59 if let ItemKind::Struct(data, _) = &item.kind;
60 if let Some(last_field) = data.fields().last();
5099ac24 61 if let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind;
3c0e092e 62
49aad941 63 // Then check if that array is zero-sized
9ffffee4
FG
64 let length = Const::from_anon_const(cx.tcx, length.def_id);
65 let length = length.try_eval_target_usize(cx.tcx, cx.param_env);
3c0e092e
XL
66 if let Some(length) = length;
67 then {
68 length == 0
69 } else {
70 false
71 }
72 }
73}