Skip to content

Commit 3183862

Browse files
committed
ImproperCTypes: splitting definitions lint into two
First retconned commit in this change to impact rustc users: The improper_ctypes_definitions has been split into improper_c_fn_definitions and improper_c_callbacks, with the former lint name being turned into a lint group, so that users aren't forced to immediately change their code. Deprecating this old name will be left as an exercise to whichever team is in charge of breaking changes. Another lint group has been created to deal with all `improper_c*` lints at once.
1 parent 971f0ab commit 3183862

File tree

61 files changed

+224
-140
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+224
-140
lines changed

compiler/rustc_codegen_cranelift/example/std_example.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ fn rust_call_abi() {
209209
struct I64X2([i64; 2]);
210210

211211
#[cfg_attr(target_arch = "s390x", allow(dead_code))]
212-
#[allow(improper_ctypes_definitions)]
212+
#[allow(improper_c_fn_definitions)]
213213
extern "C" fn foo(_a: I64X2) {}
214214

215215
#[cfg(target_arch = "x86_64")]

compiler/rustc_lint/messages.ftl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ lint_implicit_unsafe_autorefs = implicit autoref creates a reference to the dere
350350
.method_def = method calls to `{$method_name}` require a reference
351351
.suggestion = try using a raw pointer method instead; or if this reference is intentional, make it explicit
352352
353-
lint_improper_ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe
353+
lint_improper_ctypes = {$desc} uses type `{$ty}`, which is not FFI-safe
354354
.label = not FFI-safe
355355
.note = the type is defined here
356356

compiler/rustc_lint/src/lib.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,17 @@ fn register_builtins(store: &mut LintStore) {
335335
REFINING_IMPL_TRAIT_INTERNAL
336336
);
337337

338+
add_lint_group!(
339+
"improper_c_boundaries",
340+
IMPROPER_C_CALLBACKS,
341+
IMPROPER_C_FN_DEFINITIONS,
342+
IMPROPER_CTYPES
343+
);
344+
345+
// FIXME(ctypes, migration): when should this retrocompatibility-borne
346+
// lint group disappear, if at all? Should it turn into a register_renamed?
347+
add_lint_group!("improper_ctypes_definitions", IMPROPER_C_CALLBACKS, IMPROPER_C_FN_DEFINITIONS);
348+
338349
add_lint_group!("deprecated_safe", DEPRECATED_SAFE_2024);
339350

340351
add_lint_group!(

compiler/rustc_lint/src/types.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ use tracing::debug;
1111
use {rustc_ast as ast, rustc_hir as hir};
1212

1313
mod improper_ctypes; // these filed do the implementation for ImproperCTypesDefinitions,ImproperCTypesDeclarations
14-
pub(crate) use improper_ctypes::ImproperCTypesLint;
14+
pub(crate) use improper_ctypes::{
15+
IMPROPER_C_CALLBACKS, IMPROPER_C_FN_DEFINITIONS, IMPROPER_CTYPES, ImproperCTypesLint,
16+
};
1517

1618
use crate::lints::{
1719
AmbiguousWidePointerComparisons, AmbiguousWidePointerComparisonsAddrMetadataSuggestion,

compiler/rustc_lint/src/types/improper_ctypes.rs

Lines changed: 97 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,14 @@ use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
2626
declare_lint! {
2727
/// The `improper_ctypes` lint detects incorrect use of types in foreign
2828
/// modules.
29+
/// (In other words, declarations of items defined in foreign code.)
2930
///
3031
/// ### Example
3132
///
3233
/// ```rust
3334
/// unsafe extern "C" {
3435
/// static STATIC: String;
36+
/// fn some_func(a:String);
3537
/// }
3638
/// ```
3739
///
@@ -45,14 +47,15 @@ declare_lint! {
4547
/// detects a probable mistake in a definition. The lint usually should
4648
/// provide a description of the issue, along with possibly a hint on how
4749
/// to resolve it.
48-
IMPROPER_CTYPES,
50+
pub(crate) IMPROPER_CTYPES,
4951
Warn,
5052
"proper use of libc types in foreign modules"
5153
}
5254

5355
declare_lint! {
54-
/// The `improper_ctypes_definitions` lint detects incorrect use of
56+
/// The `improper_c_fn_definitions` lint detects incorrect use of
5557
/// [`extern` function] definitions.
58+
/// (In other words, functions to be used by foreign code.)
5659
///
5760
/// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
5861
///
@@ -72,11 +75,39 @@ declare_lint! {
7275
/// lint is an alert that these types should not be used. The lint usually
7376
/// should provide a description of the issue, along with possibly a hint
7477
/// on how to resolve it.
75-
IMPROPER_CTYPES_DEFINITIONS,
78+
pub(crate) IMPROPER_C_FN_DEFINITIONS,
7679
Warn,
7780
"proper use of libc types in foreign item definitions"
7881
}
7982

83+
declare_lint! {
84+
/// The `improper_c_callbacks` lint detects incorrect use of
85+
/// [`extern` function] pointers.
86+
/// (In other words, function signatures for callbacks.)
87+
///
88+
/// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
89+
///
90+
/// ### Example
91+
///
92+
/// ```rust
93+
/// # #![allow(unused)]
94+
/// pub fn str_emmiter(call_me_back: extern "C" fn(&str)) { }
95+
/// ```
96+
///
97+
/// {{produces}}
98+
///
99+
/// ### Explanation
100+
///
101+
/// There are many parameter and return types that may be specified in an
102+
/// `extern` function that are not compatible with the given ABI. This
103+
/// lint is an alert that these types should not be used. The lint usually
104+
/// should provide a description of the issue, along with possibly a hint
105+
/// on how to resolve it.
106+
pub(crate) IMPROPER_C_CALLBACKS,
107+
Warn,
108+
"proper use of libc types in foreign-code-compatible callbacks"
109+
}
110+
80111
declare_lint! {
81112
/// The `uses_power_alignment` lint detects specific `repr(C)`
82113
/// aggregates on AIX.
@@ -134,8 +165,9 @@ declare_lint! {
134165

135166
declare_lint_pass!(ImproperCTypesLint => [
136167
IMPROPER_CTYPES,
137-
IMPROPER_CTYPES_DEFINITIONS,
138-
USES_POWER_ALIGNMENT
168+
IMPROPER_C_FN_DEFINITIONS,
169+
IMPROPER_C_CALLBACKS,
170+
USES_POWER_ALIGNMENT,
139171
]);
140172

141173
/// Getting the (normalized) type out of a field (for, e.g., an enum variant or a tuple).
@@ -185,10 +217,17 @@ fn variant_has_complex_ctor(variant: &ty::VariantDef) -> bool {
185217
!matches!(variant.ctor_kind(), Some(CtorKind::Const))
186218
}
187219

188-
#[derive(Clone, Copy)]
220+
/// A way to keep track of what we want to lint for FFI-safety.
221+
/// In other words, the nature of the "original item" being checked, and its relation
222+
/// to FFI boundaries.
223+
#[derive(Clone, Copy, Debug)]
189224
enum CItemKind {
190-
Declaration,
191-
Definition,
225+
/// Imported items in an `extern "C"` block (function declarations, static variables) -> IMPROPER_CTYPES
226+
ImportedExtern,
227+
/// `extern "C"` function definitions, to be used elsewhere -> IMPROPER_C_FN_DEFINITIONS,
228+
ExportedFunction,
229+
/// `extern "C"` function pointers -> IMPROPER_C_CALLBACKS,
230+
Callback,
192231
}
193232

194233
#[derive(Clone, Debug)]
@@ -428,16 +467,22 @@ impl VisitorState {
428467
/// Get the proper visitor state for a given function's arguments.
429468
fn argument_from_fnmode(fn_mode: CItemKind) -> Self {
430469
match fn_mode {
431-
CItemKind::Definition => VisitorState::ARGUMENT_TY_IN_DEFINITION,
432-
CItemKind::Declaration => VisitorState::ARGUMENT_TY_IN_DECLARATION,
470+
CItemKind::ExportedFunction => VisitorState::ARGUMENT_TY_IN_DEFINITION,
471+
CItemKind::ImportedExtern => VisitorState::ARGUMENT_TY_IN_DECLARATION,
472+
// we could also deal with CItemKind::Callback,
473+
// but we bake an assumption from this function's call sites here.
474+
_ => bug!("cannot be called with CItemKind::{:?}", fn_mode),
433475
}
434476
}
435477

436478
/// Get the proper visitor state for a given function's return type.
437479
fn return_from_fnmode(fn_mode: CItemKind) -> Self {
438480
match fn_mode {
439-
CItemKind::Definition => VisitorState::RETURN_TY_IN_DEFINITION,
440-
CItemKind::Declaration => VisitorState::RETURN_TY_IN_DECLARATION,
481+
CItemKind::ExportedFunction => VisitorState::RETURN_TY_IN_DEFINITION,
482+
CItemKind::ImportedExtern => VisitorState::RETURN_TY_IN_DECLARATION,
483+
// we could also deal with CItemKind::Callback,
484+
// but we bake an assumption from this function's call sites here.
485+
_ => bug!("cannot be called with CItemKind::{:?}", fn_mode),
441486
}
442487
}
443488

@@ -566,7 +611,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
566611
IndirectionType::Box => {
567612
// FIXME(ctypes): this logic is broken, but it still fits the current tests
568613
if state.is_in_defined_function()
569-
|| (state.is_in_fnptr() && matches!(self.base_fn_mode, CItemKind::Definition))
614+
|| (state.is_in_fnptr()
615+
&& matches!(self.base_fn_mode, CItemKind::ExportedFunction))
570616
{
571617
if inner_ty.is_sized(tcx, self.cx.typing_env()) {
572618
return FfiSafe;
@@ -1102,7 +1148,7 @@ impl<'tcx> ImproperCTypesLint {
11021148
// FIXME(ctypes): make a check_for_fnptr
11031149
let ffi_res = visitor.check_type(state, fn_ptr_ty);
11041150

1105-
self.process_ffi_result(cx, span, ffi_res, fn_mode);
1151+
self.process_ffi_result(cx, span, ffi_res, CItemKind::Callback);
11061152
}
11071153
}
11081154

@@ -1148,9 +1194,9 @@ impl<'tcx> ImproperCTypesLint {
11481194

11491195
fn check_foreign_static(&self, cx: &LateContext<'tcx>, id: hir::OwnerId, span: Span) {
11501196
let ty = cx.tcx.type_of(id).instantiate_identity();
1151-
let visitor = ImproperCTypesVisitor::new(cx, ty, CItemKind::Declaration);
1197+
let visitor = ImproperCTypesVisitor::new(cx, ty, CItemKind::ImportedExtern);
11521198
let ffi_res = visitor.check_type(VisitorState::STATIC_TY, ty);
1153-
self.process_ffi_result(cx, span, ffi_res, CItemKind::Declaration);
1199+
self.process_ffi_result(cx, span, ffi_res, CItemKind::ImportedExtern);
11541200
}
11551201

11561202
/// Check if a function's argument types and result type are "ffi-safe".
@@ -1165,16 +1211,16 @@ impl<'tcx> ImproperCTypesLint {
11651211
let sig = cx.tcx.instantiate_bound_regions_with_erased(sig);
11661212

11671213
for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
1168-
let state = VisitorState::argument_from_fnmode(fn_mode);
1214+
let visit_state = VisitorState::argument_from_fnmode(fn_mode);
11691215
let visitor = ImproperCTypesVisitor::new(cx, *input_ty, fn_mode);
1170-
let ffi_res = visitor.check_type(state, *input_ty);
1216+
let ffi_res = visitor.check_type(visit_state, *input_ty);
11711217
self.process_ffi_result(cx, input_hir.span, ffi_res, fn_mode);
11721218
}
11731219

11741220
if let hir::FnRetTy::Return(ret_hir) = decl.output {
1175-
let state = VisitorState::return_from_fnmode(fn_mode);
1221+
let visit_state = VisitorState::return_from_fnmode(fn_mode);
11761222
let visitor = ImproperCTypesVisitor::new(cx, sig.output(), fn_mode);
1177-
let ffi_res = visitor.check_type(state, sig.output());
1223+
let ffi_res = visitor.check_type(visit_state, sig.output());
11781224
self.process_ffi_result(cx, ret_hir.span, ffi_res, fn_mode);
11791225
}
11801226
}
@@ -1251,12 +1297,14 @@ impl<'tcx> ImproperCTypesLint {
12511297
fn_mode: CItemKind,
12521298
) {
12531299
let lint = match fn_mode {
1254-
CItemKind::Declaration => IMPROPER_CTYPES,
1255-
CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS,
1300+
CItemKind::ImportedExtern => IMPROPER_CTYPES,
1301+
CItemKind::ExportedFunction => IMPROPER_C_FN_DEFINITIONS,
1302+
CItemKind::Callback => IMPROPER_C_CALLBACKS,
12561303
};
12571304
let desc = match fn_mode {
1258-
CItemKind::Declaration => "block",
1259-
CItemKind::Definition => "fn",
1305+
CItemKind::ImportedExtern => "`extern` block",
1306+
CItemKind::ExportedFunction => "`extern` fn",
1307+
CItemKind::Callback => "`extern` callback",
12601308
};
12611309
for reason in reasons.iter_mut() {
12621310
reason.span_note = if let ty::Adt(def, _) = reason.ty.kind()
@@ -1272,13 +1320,21 @@ impl<'tcx> ImproperCTypesLint {
12721320
}
12731321
}
12741322

1275-
/// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
1276-
/// `extern "C" { }` blocks):
1323+
/// IMPROPER_CTYPES checks items that are part of a header to a non-rust library
1324+
/// Namely, functions and static variables in `extern "<abi>" { }`,
1325+
/// if `<abi>` is external (e.g. "C").
1326+
///
1327+
/// `IMPROPER_C_CALLBACKS` checks for function pointers marked with an external ABI.
1328+
/// (fields of type `extern "<abi>" fn`, where e.g. `<abi>` is `C`)
1329+
/// These pointers are searched in all other items which contain types
1330+
/// (e.g.functions, struct definitions, etc)
1331+
///
1332+
/// `IMPROPER_C_FN_DEFINITIONS` checks rust-defined functions that are marked
1333+
/// to be used from the other side of a FFI boundary.
1334+
/// In other words, `extern "<abi>" fn` definitions and trait-method declarations.
1335+
/// This only matters if `<abi>` is external (e.g. `C`).
12771336
///
1278-
/// - `extern "<abi>" fn` definitions are checked in the same way as the
1279-
/// `ImproperCtypesDeclarations` visitor checks functions if `<abi>` is external (e.g. "C").
1280-
/// - All other items which contain types (e.g. other functions, struct definitions, etc) are
1281-
/// checked for extern fn-ptrs with external ABIs.
1337+
/// and now combinatorics for pointees
12821338
impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
12831339
fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, it: &hir::ForeignItem<'tcx>) {
12841340
let abi = cx.tcx.hir_get_foreign_abi(it.hir_id());
@@ -1289,11 +1345,16 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
12891345
// "the element rendered unsafe" because their unsafety doesn't affect
12901346
// their surroundings, and their type is often declared inline
12911347
if !abi.is_rustic_abi() {
1292-
self.check_foreign_fn(cx, CItemKind::Declaration, it.owner_id.def_id, sig.decl);
1348+
self.check_foreign_fn(
1349+
cx,
1350+
CItemKind::ImportedExtern,
1351+
it.owner_id.def_id,
1352+
sig.decl,
1353+
);
12931354
} else {
12941355
self.check_fn_for_external_abi_fnptr(
12951356
cx,
1296-
CItemKind::Declaration,
1357+
CItemKind::ImportedExtern,
12971358
it.owner_id.def_id,
12981359
sig.decl,
12991360
);
@@ -1316,7 +1377,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
13161377
VisitorState::STATIC_TY,
13171378
ty,
13181379
cx.tcx.type_of(item.owner_id).instantiate_identity(),
1319-
CItemKind::Definition,
1380+
CItemKind::ExportedFunction, // TODO: for some reason, this is the value that reproduces old behaviour
13201381
);
13211382
}
13221383
// See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
@@ -1350,7 +1411,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
13501411
VisitorState::STATIC_TY,
13511412
field.ty,
13521413
cx.tcx.type_of(field.def_id).instantiate_identity(),
1353-
CItemKind::Definition,
1414+
CItemKind::ImportedExtern,
13541415
);
13551416
}
13561417

@@ -1375,9 +1436,9 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
13751436
// "the element rendered unsafe" because their unsafety doesn't affect
13761437
// their surroundings, and their type is often declared inline
13771438
if !abi.is_rustic_abi() {
1378-
self.check_foreign_fn(cx, CItemKind::Definition, id, decl);
1439+
self.check_foreign_fn(cx, CItemKind::ExportedFunction, id, decl);
13791440
} else {
1380-
self.check_fn_for_external_abi_fnptr(cx, CItemKind::Definition, id, decl);
1441+
self.check_fn_for_external_abi_fnptr(cx, CItemKind::ExportedFunction, id, decl);
13811442
}
13821443
}
13831444
}

library/panic_abort/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use core::any::Any;
2323
use core::panic::PanicPayload;
2424

2525
#[rustc_std_internal_symbol]
26-
#[allow(improper_ctypes_definitions)]
26+
#[allow(improper_c_fn_definitions)]
2727
pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Send + 'static) {
2828
unreachable!()
2929
}

library/panic_unwind/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ unsafe extern "C" {
9595
}
9696

9797
#[rustc_std_internal_symbol]
98-
#[allow(improper_ctypes_definitions)]
98+
#[allow(improper_c_fn_definitions)]
9999
pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static) {
100100
unsafe { Box::into_raw(imp::cleanup(payload)) }
101101
}

src/tools/clippy/tests/ui/inherent_to_string.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![allow(improper_ctypes_definitions)]
1+
#![allow(improper_c_fn_definitions)]
22

33
use std::fmt;
44

src/tools/lint-docs/src/groups.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
3030
"unknown-or-malformed-diagnostic-attributes",
3131
"detects unknown or malformed diagnostic attributes",
3232
),
33+
("improper-c-boundaries", "Lints for points where rust code interacts with non-rust code"),
34+
(
35+
"improper-ctypes-definitions",
36+
"Former lint that was since split intoimproper-c-fn-definitions and improper-c-callbacks",
37+
),
3338
];
3439

3540
type LintGroups = BTreeMap<String, BTreeSet<String>>;

src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//@only-target: x86_64
2-
#![allow(improper_ctypes_definitions)]
2+
#![allow(improper_c_fn_definitions)]
33
use std::arch::x86_64::*;
44
use std::mem::transmute;
55

0 commit comments

Comments
 (0)