Skip to content

Commit

Permalink
Merge pull request rust-lang#4 from surechen/stable
Browse files Browse the repository at this point in the history
add lint extern_without_repr
  • Loading branch information
surechen authored Jun 26, 2023
2 parents 3a413b7 + a74a6b5 commit cde5797
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 1 deletion.
1 change: 1 addition & 0 deletions clippy_lints/src/declared_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::exhaustive_items::EXHAUSTIVE_STRUCTS_INFO,
crate::exit::EXIT_INFO,
crate::explicit_write::EXPLICIT_WRITE_INFO,
crate::extern_without_repr::EXTERN_WITHOUT_REPR_INFO,
crate::extra_unused_type_parameters::EXTRA_UNUSED_TYPE_PARAMETERS_INFO,
crate::fallible_impl_from::FALLIBLE_IMPL_FROM_INFO,
crate::float_literal::EXCESSIVE_PRECISION_INFO,
Expand Down
97 changes: 97 additions & 0 deletions clippy_lints/src/extern_without_repr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
use rustc_hir::{ForeignItemKind, Item, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};

use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_with_applicability;
use rustc_errors::Applicability;
//use rustc_hir::{Item, ItemKind};
use clippy_utils::ty::walk_ptrs_hir_ty;
use if_chain::if_chain;
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_target::spec::abi::Abi;

declare_clippy_lint! {
/// ### What it does
///
/// ### Why is this bad?
///
/// ### Example
/// ```rust
/// struct Foo3 {
/// a: libc::c_char,
/// b: libc::c_int,
/// c: libc::c_longlong,
/// }
/// extern "C" fn c_abi_fn4(arg_one: u32, arg_two: *const Foo3) {}
/// ```
/// Use instead:
/// ```rust
/// #[repr(C)]
/// struct Foo3 {
/// a: libc::c_char,
/// b: libc::c_int,
/// c: libc::c_longlong,
/// }
/// extern "C" fn c_abi_fn4(arg_one: u32, arg_two: *const Foo3) {}
/// ```
#[clippy::version = "1.72.0"]
pub EXTERN_WITHOUT_REPR,
pedantic,
"Should use repr to specifing data layout when struct is used in FFI"
}
declare_lint_pass!(ExternWithoutRepr => [EXTERN_WITHOUT_REPR]);

impl<'tcx> LateLintPass<'tcx> for ExternWithoutRepr {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
let msg = "Should use repr to specifing data layout when struct is used in FFI";
if let ItemKind::Fn(fn_sig, _, _) = &item.kind {
let mut app = Applicability::MaybeIncorrect;
let snippet = snippet_with_applicability(cx, fn_sig.span, "..", &mut app);
if let Some((fn_attrs, _)) = snippet.split_once("fn") {
if fn_attrs.contains("extern \"C\"") {
for i in 0..fn_sig.decl.inputs.len() {
let t = hir_ty_to_ty(cx.tcx, walk_ptrs_hir_ty(&fn_sig.decl.inputs[i]));
if let Some(adt) = t.ty_adt_def() {
let repr = adt.repr();
if repr.packed() || repr.transparent() || repr.c() || repr.align.is_some() {
continue;
}
let struct_span = cx.tcx.def_span(adt.did());
span_lint_and_then(cx, EXTERN_WITHOUT_REPR, struct_span, msg, |_| {});
}
}
}
}
}

if_chain! {
if let ItemKind::ForeignMod { abi, items } = &item.kind;
if let Abi::C { unwind: _ } = abi;
then {
for i in 0..items.len() {
if let Some(Node::ForeignItem(f)) = cx.tcx.hir().find(items[i].id.hir_id()) {
if let ForeignItemKind::Fn(decl, ..) = f.kind {
for j in 0..decl.inputs.len() {
let t = hir_ty_to_ty(cx.tcx, walk_ptrs_hir_ty(&decl.inputs[j]));
if let Some(adt) = t.ty_adt_def() {
let repr = adt.repr();
if repr.packed()
|| repr.transparent()
|| repr.c()
|| repr.simd()
|| repr.align.is_some()
{
continue;
}
let struct_span = cx.tcx.def_span(adt.did());
span_lint_and_then(cx, EXTERN_WITHOUT_REPR, struct_span, msg, |_| {});
}
}
}
}
}
}
}
}
}
2 changes: 2 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ mod excessive_bools;
mod exhaustive_items;
mod exit;
mod explicit_write;
mod extern_without_repr;
mod extra_unused_type_parameters;
mod fallible_impl_from;
mod float_literal;
Expand Down Expand Up @@ -970,6 +971,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_early_pass(|| Box::new(implicit_abi::ImplicitAbi));
store.register_early_pass(|| Box::new(non_reentrant_functions::NonReentrantFunctions));
store.register_early_pass(|| Box::new(loop_without_break_or_return::LoopWithoutBreakOrReturn));
store.register_late_pass(|_| Box::new(extern_without_repr::ExternWithoutRepr));
// add lints here, do not remove this comment, it's used in `new_lint`
}

Expand Down
1 change: 1 addition & 0 deletions tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
max-struct-bools
max-suggested-slice-pattern-length
max-trait-bounds
mem-unsafe-functions
missing-docs-in-crate-items
msrv
pass-by-value-size-limit
Expand Down
44 changes: 44 additions & 0 deletions tests/ui/extern_without_repr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#![allow(unused)]
#![allow(improper_ctypes_definitions)]
#![allow(improper_ctypes)]
#![warn(clippy::extern_without_repr)]
#![feature(rustc_private)]
#![feature(core_intrinsics)]
extern crate libc;

#[repr(C)]
struct Foo1 {
a: i32,
b: i64,
c: u128,
}

#[repr(packed)]
#[derive(Debug)]
struct Foo2 {
a: libc::c_char,
b: libc::c_int,
c: libc::c_longlong,
}

struct Foo3 {
a: libc::c_char,
b: libc::c_int,
c: libc::c_longlong,
}

extern "C" fn c_abi_fn1(arg_one: u32, arg_two: usize) {}
extern "C" fn c_abi_fn2(arg_one: u32, arg_two: Foo1) {}
extern "C" fn c_abi_fn3(arg_one: u32, arg_two: *const Foo2) {}
extern "C" fn c_abi_fn4(arg_one: u32, arg_two: *const Foo3) {}

extern "C" {
fn c_abi_in_block1(arg_one: u32, arg_two: usize);
fn c_abi_in_block2(arg_one: u32, arg_two: Foo1);
fn c_abi_in_block3(arg_one: u32, arg_two: Foo2);
fn c_abi_in_block4(arg_one: u32, arg_two: Foo3);
}

fn main() {
// test code goes here
}
10 changes: 10 additions & 0 deletions tests/ui/extern_without_repr.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: Should use repr to specifing data layout when struct is used in FFI
--> $DIR/extern_without_repr.rs:24:1
|
LL | struct Foo3 {
| ^^^^^^^^^^^
|
= note: `-D clippy::extern-without-repr` implied by `-D warnings`

error: aborting due to previous error

12 changes: 11 additions & 1 deletion tests/ui/non_reentrant_functions.stderr
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
error[E0425]: cannot find function `localtime` in crate `libc`
--> $DIR/non_reentrant_functions.rs:11:25
|
LL | let _tm = libc::localtime(&0i64 as *const libc::time_t);
| ^^^^^^^^^ help: a function with a similar name exists: `localtime_s`
--> C:/Users/runneradmin/.cargo/registry/src/index.crates.io-6f17d22bba15001f/libc-0.2.140/src/windows/mod.rs:392:5
|
= note: similarly named function `localtime_s` defined here

error: consider using the reentrant version of the function
--> $DIR/non_reentrant_functions.rs:11:19
|
Expand All @@ -18,5 +27,6 @@ error: consider using the reentrant version of the function
LL | token = unsafe { libc::strtok(std::ptr::null_mut(), delim) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 3 previous errors
error: aborting due to 4 previous errors

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

0 comments on commit cde5797

Please sign in to comment.