Skip to content

Commit 0112cca

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 1470565 commit 0112cca

File tree

62 files changed

+224
-144
lines changed

Some content is hidden

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

62 files changed

+224
-144
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
@@ -70,10 +70,17 @@ fn variant_has_complex_ctor(variant: &ty::VariantDef) -> bool {
7070
!matches!(variant.ctor_kind(), Some(CtorKind::Const))
7171
}
7272

73-
#[derive(Clone, Copy)]
73+
/// A way to keep track of what we want to lint for FFI-safety.
74+
/// In other words, the nature of the "original item" being checked, and its relation
75+
/// to FFI boundaries.
76+
#[derive(Clone, Copy, Debug)]
7477
enum CItemKind {
75-
Declaration,
76-
Definition,
78+
/// Imported items in an `extern "C"` block (function declarations, static variables) -> IMPROPER_CTYPES
79+
ImportedExtern,
80+
/// `extern "C"` function definitions, to be used elsewhere -> IMPROPER_C_FN_DEFINITIONS,
81+
ExportedFunction,
82+
/// `extern "C"` function pointers -> IMPROPER_C_CALLBACKS,
83+
Callback,
7784
}
7885

7986
#[derive(Clone, Debug)]
@@ -301,16 +308,22 @@ impl VisitorState {
301308
/// Get the proper visitor state for a given function's arguments.
302309
fn argument_from_fnmode(fn_mode: CItemKind) -> Self {
303310
match fn_mode {
304-
CItemKind::Definition => VisitorState::ArgumentTyInDefinition,
305-
CItemKind::Declaration => VisitorState::ArgumentTyInDeclaration,
311+
CItemKind::ExportedFunction => VisitorState::ArgumentTyInDefinition,
312+
CItemKind::ImportedExtern => VisitorState::ArgumentTyInDeclaration,
313+
// we could also deal with CItemKind::Callback,
314+
// but we bake an assumption from this function's call sites here.
315+
_ => bug!("cannot be called with CItemKind::{:?}", fn_mode),
306316
}
307317
}
308318

309319
/// Get the proper visitor state for a given function's return type.
310320
fn return_from_fnmode(fn_mode: CItemKind) -> Self {
311321
match fn_mode {
312-
CItemKind::Definition => VisitorState::ReturnTyInDefinition,
313-
CItemKind::Declaration => VisitorState::ReturnTyInDeclaration,
322+
CItemKind::ExportedFunction => VisitorState::ReturnTyInDefinition,
323+
CItemKind::ImportedExtern => VisitorState::ReturnTyInDeclaration,
324+
// we could also deal with CItemKind::Callback,
325+
// but we bake an assumption from this function's call sites here.
326+
_ => bug!("cannot be called with CItemKind::{:?}", fn_mode),
314327
}
315328
}
316329

@@ -440,7 +453,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
440453
IndirectionType::Box => {
441454
// TODO: this logic is broken, but it still fits the current tests
442455
if state.is_in_defined_function()
443-
|| (state.is_in_fnptr() && matches!(self.base_fn_mode, CItemKind::Definition))
456+
|| (state.is_in_fnptr()
457+
&& matches!(self.base_fn_mode, CItemKind::ExportedFunction))
444458
{
445459
if inner_ty.is_sized(tcx, self.cx.typing_env()) {
446460
return FfiSafe;
@@ -981,7 +995,7 @@ impl<'tcx> ImproperCTypesLint {
981995
// TODO: make a check_for_fnptr
982996
let ffi_res = visitor.check_for_type(state, fn_ptr_ty);
983997

984-
self.process_ffi_result(cx, span, ffi_res, fn_mode)
998+
self.process_ffi_result(cx, span, ffi_res, CItemKind::Callback)
985999
});
9861000
}
9871001

@@ -1027,9 +1041,9 @@ impl<'tcx> ImproperCTypesLint {
10271041

10281042
fn check_foreign_static(&self, cx: &LateContext<'tcx>, id: hir::OwnerId, span: Span) {
10291043
let ty = cx.tcx.type_of(id).instantiate_identity();
1030-
let visitor = ImproperCTypesVisitor::new(cx, ty, CItemKind::Declaration);
1044+
let visitor = ImproperCTypesVisitor::new(cx, ty, CItemKind::ImportedExtern);
10311045
let ffi_res = visitor.check_for_type(VisitorState::StaticTy, ty);
1032-
self.process_ffi_result(cx, span, ffi_res, CItemKind::Declaration);
1046+
self.process_ffi_result(cx, span, ffi_res, CItemKind::ImportedExtern);
10331047
}
10341048

10351049
/// Check if a function's argument types and result type are "ffi-safe".
@@ -1044,16 +1058,16 @@ impl<'tcx> ImproperCTypesLint {
10441058
let sig = cx.tcx.instantiate_bound_regions_with_erased(sig);
10451059

10461060
for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
1047-
let state = VisitorState::argument_from_fnmode(fn_mode);
1061+
let visit_state = VisitorState::argument_from_fnmode(fn_mode);
10481062
let visitor = ImproperCTypesVisitor::new(cx, *input_ty, fn_mode);
1049-
let ffi_res = visitor.check_for_type(state, *input_ty);
1063+
let ffi_res = visitor.check_for_type(visit_state, *input_ty);
10501064
self.process_ffi_result(cx, input_hir.span, ffi_res, fn_mode);
10511065
}
10521066

10531067
if let hir::FnRetTy::Return(ret_hir) = decl.output {
1054-
let state = VisitorState::return_from_fnmode(fn_mode);
1068+
let visit_state = VisitorState::return_from_fnmode(fn_mode);
10551069
let visitor = ImproperCTypesVisitor::new(cx, sig.output(), fn_mode);
1056-
let ffi_res = visitor.check_for_type(state, sig.output());
1070+
let ffi_res = visitor.check_for_type(visit_state, sig.output());
10571071
self.process_ffi_result(cx, ret_hir.span, ffi_res, fn_mode);
10581072
}
10591073
}
@@ -1130,12 +1144,14 @@ impl<'tcx> ImproperCTypesLint {
11301144
fn_mode: CItemKind,
11311145
) {
11321146
let lint = match fn_mode {
1133-
CItemKind::Declaration => IMPROPER_CTYPES,
1134-
CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS,
1147+
CItemKind::ImportedExtern => IMPROPER_CTYPES,
1148+
CItemKind::ExportedFunction => IMPROPER_C_FN_DEFINITIONS,
1149+
CItemKind::Callback => IMPROPER_C_CALLBACKS,
11351150
};
11361151
let desc = match fn_mode {
1137-
CItemKind::Declaration => "block",
1138-
CItemKind::Definition => "fn",
1152+
CItemKind::ImportedExtern => "`extern` block",
1153+
CItemKind::ExportedFunction => "`extern` fn",
1154+
CItemKind::Callback => "`extern` callback",
11391155
};
11401156
for reason in reasons.iter_mut() {
11411157
reason.span_note = if let ty::Adt(def, _) = reason.ty.kind()
@@ -1151,13 +1167,21 @@ impl<'tcx> ImproperCTypesLint {
11511167
}
11521168
}
11531169

1154-
/// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
1155-
/// `extern "C" { }` blocks):
1170+
/// IMPROPER_CTYPES checks items that are part of a header to a non-rust library
1171+
/// Namely, functions and static variables in `extern "<abi>" { }`,
1172+
/// if `<abi>` is external (e.g. "C").
1173+
///
1174+
/// `IMPROPER_C_CALLBACKS` checks for function pointers marked with an external ABI.
1175+
/// (fields of type `extern "<abi>" fn`, where e.g. `<abi>` is `C`)
1176+
/// These pointers are searched in all other items which contain types
1177+
/// (e.g.functions, struct definitions, etc)
1178+
///
1179+
/// `IMPROPER_C_FN_DEFINITIONS` checks rust-defined functions that are marked
1180+
/// to be used from the other side of a FFI boundary.
1181+
/// In other words, `extern "<abi>" fn` definitions and trait-method declarations.
1182+
/// This only matters if `<abi>` is external (e.g. `C`).
11561183
///
1157-
/// - `extern "<abi>" fn` definitions are checked in the same way as the
1158-
/// `ImproperCtypesDeclarations` visitor checks functions if `<abi>` is external (e.g. "C").
1159-
/// - All other items which contain types (e.g. other functions, struct definitions, etc) are
1160-
/// checked for extern fn-ptrs with external ABIs.
1184+
/// and now combinatorics for pointees
11611185
impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
11621186
fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, it: &hir::ForeignItem<'tcx>) {
11631187
let abi = cx.tcx.hir_get_foreign_abi(it.hir_id());
@@ -1168,11 +1192,16 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
11681192
// "the element rendered unsafe" because their unsafety doesn't affect
11691193
// their surroundings, and their type is often declared inline
11701194
if !abi.is_rustic_abi() {
1171-
self.check_foreign_fn(cx, CItemKind::Declaration, it.owner_id.def_id, sig.decl);
1195+
self.check_foreign_fn(
1196+
cx,
1197+
CItemKind::ImportedExtern,
1198+
it.owner_id.def_id,
1199+
sig.decl,
1200+
);
11721201
} else {
11731202
self.check_fn_for_external_abi_fnptr(
11741203
cx,
1175-
CItemKind::Declaration,
1204+
CItemKind::ImportedExtern,
11761205
it.owner_id.def_id,
11771206
sig.decl,
11781207
);
@@ -1195,7 +1224,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
11951224
VisitorState::StaticTy,
11961225
ty,
11971226
cx.tcx.type_of(item.owner_id).instantiate_identity(),
1198-
CItemKind::Definition,
1227+
CItemKind::ExportedFunction, // TODO: for some reason, this is the value that reproduces old behaviour
11991228
);
12001229
}
12011230
// See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
@@ -1229,7 +1258,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
12291258
VisitorState::StaticTy,
12301259
field.ty,
12311260
cx.tcx.type_of(field.def_id).instantiate_identity(),
1232-
CItemKind::Definition,
1261+
CItemKind::ImportedExtern,
12331262
);
12341263
}
12351264

@@ -1254,22 +1283,24 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
12541283
// "the element rendered unsafe" because their unsafety doesn't affect
12551284
// their surroundings, and their type is often declared inline
12561285
if !abi.is_rustic_abi() {
1257-
self.check_foreign_fn(cx, CItemKind::Definition, id, decl);
1286+
self.check_foreign_fn(cx, CItemKind::ExportedFunction, id, decl);
12581287
} else {
1259-
self.check_fn_for_external_abi_fnptr(cx, CItemKind::Definition, id, decl);
1288+
self.check_fn_for_external_abi_fnptr(cx, CItemKind::ExportedFunction, id, decl);
12601289
}
12611290
}
12621291
}
12631292

12641293
declare_lint! {
12651294
/// The `improper_ctypes` lint detects incorrect use of types in foreign
12661295
/// modules.
1296+
/// (In other words, declarations of items defined in foreign code.)
12671297
///
12681298
/// ### Example
12691299
///
12701300
/// ```rust
12711301
/// unsafe extern "C" {
12721302
/// static STATIC: String;
1303+
/// fn some_func(a:String);
12731304
/// }
12741305
/// ```
12751306
///
@@ -1283,14 +1314,15 @@ declare_lint! {
12831314
/// detects a probable mistake in a definition. The lint usually should
12841315
/// provide a description of the issue, along with possibly a hint on how
12851316
/// to resolve it.
1286-
IMPROPER_CTYPES,
1317+
pub(crate) IMPROPER_CTYPES,
12871318
Warn,
12881319
"proper use of libc types in foreign modules"
12891320
}
12901321

12911322
declare_lint! {
1292-
/// The `improper_ctypes_definitions` lint detects incorrect use of
1323+
/// The `improper_c_fn_definitions` lint detects incorrect use of
12931324
/// [`extern` function] definitions.
1325+
/// (In other words, functions to be used by foreign code.)
12941326
///
12951327
/// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
12961328
///
@@ -1310,11 +1342,39 @@ declare_lint! {
13101342
/// lint is an alert that these types should not be used. The lint usually
13111343
/// should provide a description of the issue, along with possibly a hint
13121344
/// on how to resolve it.
1313-
IMPROPER_CTYPES_DEFINITIONS,
1345+
pub(crate) IMPROPER_C_FN_DEFINITIONS,
13141346
Warn,
13151347
"proper use of libc types in foreign item definitions"
13161348
}
13171349

1350+
declare_lint! {
1351+
/// The `improper_c_callbacks` lint detects incorrect use of
1352+
/// [`extern` function] pointers.
1353+
/// (In other words, function signatures for callbacks.)
1354+
///
1355+
/// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
1356+
///
1357+
/// ### Example
1358+
///
1359+
/// ```rust
1360+
/// # #![allow(unused)]
1361+
/// pub fn str_emmiter(call_me_back: extern "C" fn(&str)) { }
1362+
/// ```
1363+
///
1364+
/// {{produces}}
1365+
///
1366+
/// ### Explanation
1367+
///
1368+
/// There are many parameter and return types that may be specified in an
1369+
/// `extern` function that are not compatible with the given ABI. This
1370+
/// lint is an alert that these types should not be used. The lint usually
1371+
/// should provide a description of the issue, along with possibly a hint
1372+
/// on how to resolve it.
1373+
pub(crate) IMPROPER_C_CALLBACKS,
1374+
Warn,
1375+
"proper use of libc types in foreign-code-compatible callbacks"
1376+
}
1377+
13181378
declare_lint! {
13191379
/// The `uses_power_alignment` lint detects specific `repr(C)`
13201380
/// aggregates on AIX.
@@ -1372,6 +1432,7 @@ declare_lint! {
13721432

13731433
declare_lint_pass!(ImproperCTypesLint => [
13741434
IMPROPER_CTYPES,
1375-
IMPROPER_CTYPES_DEFINITIONS,
1376-
USES_POWER_ALIGNMENT
1435+
IMPROPER_C_FN_DEFINITIONS,
1436+
IMPROPER_C_CALLBACKS,
1437+
USES_POWER_ALIGNMENT,
13771438
]);

library/compiler-builtins/compiler-builtins/src/lib.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@
1818
#![no_std]
1919
#![allow(unused_features)]
2020
#![allow(internal_features)]
21-
// We use `u128` in a whole bunch of places which we currently agree with the
22-
// compiler on ABIs and such, so we should be "good enough" for now and changes
23-
// to the `u128` ABI will be reflected here.
24-
#![allow(improper_ctypes, improper_ctypes_definitions)]
2521
// `mem::swap` cannot be used because it may generate references to memcpy in unoptimized code.
2622
#![allow(clippy::manual_swap)]
2723
// Support compiling on both stage0 and stage1 which may differ in supported stable features.

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>>;

0 commit comments

Comments
 (0)