Skip to content

Commit cde5797

Browse files
authored
Merge pull request rust-lang#4 from surechen/stable
add lint extern_without_repr
2 parents 3a413b7 + a74a6b5 commit cde5797

File tree

7 files changed

+166
-1
lines changed

7 files changed

+166
-1
lines changed

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
158158
crate::exhaustive_items::EXHAUSTIVE_STRUCTS_INFO,
159159
crate::exit::EXIT_INFO,
160160
crate::explicit_write::EXPLICIT_WRITE_INFO,
161+
crate::extern_without_repr::EXTERN_WITHOUT_REPR_INFO,
161162
crate::extra_unused_type_parameters::EXTRA_UNUSED_TYPE_PARAMETERS_INFO,
162163
crate::fallible_impl_from::FALLIBLE_IMPL_FROM_INFO,
163164
crate::float_literal::EXCESSIVE_PRECISION_INFO,
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
use rustc_hir::{ForeignItemKind, Item, ItemKind, Node};
2+
use rustc_lint::{LateContext, LateLintPass};
3+
use rustc_session::{declare_lint_pass, declare_tool_lint};
4+
5+
use clippy_utils::diagnostics::span_lint_and_then;
6+
use clippy_utils::source::snippet_with_applicability;
7+
use rustc_errors::Applicability;
8+
//use rustc_hir::{Item, ItemKind};
9+
use clippy_utils::ty::walk_ptrs_hir_ty;
10+
use if_chain::if_chain;
11+
use rustc_hir_analysis::hir_ty_to_ty;
12+
use rustc_target::spec::abi::Abi;
13+
14+
declare_clippy_lint! {
15+
/// ### What it does
16+
///
17+
/// ### Why is this bad?
18+
///
19+
/// ### Example
20+
/// ```rust
21+
/// struct Foo3 {
22+
/// a: libc::c_char,
23+
/// b: libc::c_int,
24+
/// c: libc::c_longlong,
25+
/// }
26+
/// extern "C" fn c_abi_fn4(arg_one: u32, arg_two: *const Foo3) {}
27+
/// ```
28+
/// Use instead:
29+
/// ```rust
30+
/// #[repr(C)]
31+
/// struct Foo3 {
32+
/// a: libc::c_char,
33+
/// b: libc::c_int,
34+
/// c: libc::c_longlong,
35+
/// }
36+
/// extern "C" fn c_abi_fn4(arg_one: u32, arg_two: *const Foo3) {}
37+
/// ```
38+
#[clippy::version = "1.72.0"]
39+
pub EXTERN_WITHOUT_REPR,
40+
pedantic,
41+
"Should use repr to specifing data layout when struct is used in FFI"
42+
}
43+
declare_lint_pass!(ExternWithoutRepr => [EXTERN_WITHOUT_REPR]);
44+
45+
impl<'tcx> LateLintPass<'tcx> for ExternWithoutRepr {
46+
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
47+
let msg = "Should use repr to specifing data layout when struct is used in FFI";
48+
if let ItemKind::Fn(fn_sig, _, _) = &item.kind {
49+
let mut app = Applicability::MaybeIncorrect;
50+
let snippet = snippet_with_applicability(cx, fn_sig.span, "..", &mut app);
51+
if let Some((fn_attrs, _)) = snippet.split_once("fn") {
52+
if fn_attrs.contains("extern \"C\"") {
53+
for i in 0..fn_sig.decl.inputs.len() {
54+
let t = hir_ty_to_ty(cx.tcx, walk_ptrs_hir_ty(&fn_sig.decl.inputs[i]));
55+
if let Some(adt) = t.ty_adt_def() {
56+
let repr = adt.repr();
57+
if repr.packed() || repr.transparent() || repr.c() || repr.align.is_some() {
58+
continue;
59+
}
60+
let struct_span = cx.tcx.def_span(adt.did());
61+
span_lint_and_then(cx, EXTERN_WITHOUT_REPR, struct_span, msg, |_| {});
62+
}
63+
}
64+
}
65+
}
66+
}
67+
68+
if_chain! {
69+
if let ItemKind::ForeignMod { abi, items } = &item.kind;
70+
if let Abi::C { unwind: _ } = abi;
71+
then {
72+
for i in 0..items.len() {
73+
if let Some(Node::ForeignItem(f)) = cx.tcx.hir().find(items[i].id.hir_id()) {
74+
if let ForeignItemKind::Fn(decl, ..) = f.kind {
75+
for j in 0..decl.inputs.len() {
76+
let t = hir_ty_to_ty(cx.tcx, walk_ptrs_hir_ty(&decl.inputs[j]));
77+
if let Some(adt) = t.ty_adt_def() {
78+
let repr = adt.repr();
79+
if repr.packed()
80+
|| repr.transparent()
81+
|| repr.c()
82+
|| repr.simd()
83+
|| repr.align.is_some()
84+
{
85+
continue;
86+
}
87+
let struct_span = cx.tcx.def_span(adt.did());
88+
span_lint_and_then(cx, EXTERN_WITHOUT_REPR, struct_span, msg, |_| {});
89+
}
90+
}
91+
}
92+
}
93+
}
94+
}
95+
}
96+
}
97+
}

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ mod excessive_bools;
123123
mod exhaustive_items;
124124
mod exit;
125125
mod explicit_write;
126+
mod extern_without_repr;
126127
mod extra_unused_type_parameters;
127128
mod fallible_impl_from;
128129
mod float_literal;
@@ -970,6 +971,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
970971
store.register_early_pass(|| Box::new(implicit_abi::ImplicitAbi));
971972
store.register_early_pass(|| Box::new(non_reentrant_functions::NonReentrantFunctions));
972973
store.register_early_pass(|| Box::new(loop_without_break_or_return::LoopWithoutBreakOrReturn));
974+
store.register_late_pass(|_| Box::new(extern_without_repr::ExternWithoutRepr));
973975
// add lints here, do not remove this comment, it's used in `new_lint`
974976
}
975977

tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
3434
max-struct-bools
3535
max-suggested-slice-pattern-length
3636
max-trait-bounds
37+
mem-unsafe-functions
3738
missing-docs-in-crate-items
3839
msrv
3940
pass-by-value-size-limit

tests/ui/extern_without_repr.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#![allow(unused)]
2+
#![allow(improper_ctypes_definitions)]
3+
#![allow(improper_ctypes)]
4+
#![warn(clippy::extern_without_repr)]
5+
#![feature(rustc_private)]
6+
#![feature(core_intrinsics)]
7+
extern crate libc;
8+
9+
#[repr(C)]
10+
struct Foo1 {
11+
a: i32,
12+
b: i64,
13+
c: u128,
14+
}
15+
16+
#[repr(packed)]
17+
#[derive(Debug)]
18+
struct Foo2 {
19+
a: libc::c_char,
20+
b: libc::c_int,
21+
c: libc::c_longlong,
22+
}
23+
24+
struct Foo3 {
25+
a: libc::c_char,
26+
b: libc::c_int,
27+
c: libc::c_longlong,
28+
}
29+
30+
extern "C" fn c_abi_fn1(arg_one: u32, arg_two: usize) {}
31+
extern "C" fn c_abi_fn2(arg_one: u32, arg_two: Foo1) {}
32+
extern "C" fn c_abi_fn3(arg_one: u32, arg_two: *const Foo2) {}
33+
extern "C" fn c_abi_fn4(arg_one: u32, arg_two: *const Foo3) {}
34+
35+
extern "C" {
36+
fn c_abi_in_block1(arg_one: u32, arg_two: usize);
37+
fn c_abi_in_block2(arg_one: u32, arg_two: Foo1);
38+
fn c_abi_in_block3(arg_one: u32, arg_two: Foo2);
39+
fn c_abi_in_block4(arg_one: u32, arg_two: Foo3);
40+
}
41+
42+
fn main() {
43+
// test code goes here
44+
}

tests/ui/extern_without_repr.stderr

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: Should use repr to specifing data layout when struct is used in FFI
2+
--> $DIR/extern_without_repr.rs:24:1
3+
|
4+
LL | struct Foo3 {
5+
| ^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::extern-without-repr` implied by `-D warnings`
8+
9+
error: aborting due to previous error
10+

tests/ui/non_reentrant_functions.stderr

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
error[E0425]: cannot find function `localtime` in crate `libc`
2+
--> $DIR/non_reentrant_functions.rs:11:25
3+
|
4+
LL | let _tm = libc::localtime(&0i64 as *const libc::time_t);
5+
| ^^^^^^^^^ help: a function with a similar name exists: `localtime_s`
6+
--> C:/Users/runneradmin/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libc-0.2.140/src/windows/mod.rs:392:5
7+
|
8+
= note: similarly named function `localtime_s` defined here
9+
110
error: consider using the reentrant version of the function
211
--> $DIR/non_reentrant_functions.rs:11:19
312
|
@@ -18,5 +27,6 @@ error: consider using the reentrant version of the function
1827
LL | token = unsafe { libc::strtok(std::ptr::null_mut(), delim) };
1928
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2029

21-
error: aborting due to 3 previous errors
30+
error: aborting due to 4 previous errors
2231

32+
For more information about this error, try `rustc --explain E0425`.

0 commit comments

Comments
 (0)