Skip to content

Commit a2dc1fb

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 764d8fb commit a2dc1fb

File tree

61 files changed

+227
-141
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

+227
-141
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: 99 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@ use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
2525
declare_lint! {
2626
/// The `improper_ctypes` lint detects incorrect use of types in foreign
2727
/// modules.
28+
/// (In other words, declarations of items defined in foreign code.)
2829
///
2930
/// ### Example
3031
///
3132
/// ```rust
3233
/// unsafe extern "C" {
3334
/// static STATIC: String;
35+
/// fn some_func(a:String);
3436
/// }
3537
/// ```
3638
///
@@ -44,14 +46,15 @@ declare_lint! {
4446
/// detects a probable mistake in a definition. The lint usually should
4547
/// provide a description of the issue, along with possibly a hint on how
4648
/// to resolve it.
47-
IMPROPER_CTYPES,
49+
pub(crate) IMPROPER_CTYPES,
4850
Warn,
4951
"proper use of libc types in foreign modules"
5052
}
5153

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

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

134165
declare_lint_pass!(ImproperCTypesLint => [
135166
IMPROPER_CTYPES,
136-
IMPROPER_CTYPES_DEFINITIONS,
137-
USES_POWER_ALIGNMENT
167+
IMPROPER_C_FN_DEFINITIONS,
168+
IMPROPER_C_CALLBACKS,
169+
USES_POWER_ALIGNMENT,
138170
]);
139171

140172
/// Getting the (normalized) type out of a field (for, e.g., an enum variant or a tuple).
@@ -254,10 +286,17 @@ fn check_struct_for_power_alignment<'tcx>(
254286
}
255287
}
256288

257-
#[derive(Clone, Copy)]
289+
/// A way to keep track of what we want to lint for FFI-safety.
290+
/// In other words, the nature of the "original item" being checked, and its relation
291+
/// to FFI boundaries.
292+
#[derive(Clone, Copy, Debug)]
258293
enum CItemKind {
259-
Declaration,
260-
Definition,
294+
/// Imported items in an `extern "C"` block (function declarations, static variables) -> IMPROPER_CTYPES
295+
ImportedExtern,
296+
/// `extern "C"` function definitions, to be used elsewhere -> IMPROPER_C_FN_DEFINITIONS,
297+
ExportedFunction,
298+
/// `extern "C"` function pointers -> IMPROPER_C_CALLBACKS,
299+
Callback,
261300
}
262301

263302
#[derive(Clone, Debug)]
@@ -472,7 +511,9 @@ bitflags! {
472511
/// (struct/enum/union definitions, FnPtrs).
473512
const THEORETICAL = 0b010000;
474513
}
514+
}
475515

516+
bitflags! {
476517
/// "Ephemeral state" flags for VisitorState (lost when visiting new mir::Ty,
477518
/// mostly contain info about the Ty immediately containing the current one).
478519
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -583,17 +624,23 @@ impl VisitorState {
583624
/// Get the proper visitor state for a given function's arguments.
584625
fn argument_from_fnmode(fn_mode: CItemKind) -> Self {
585626
let p_flags = match fn_mode {
586-
CItemKind::Definition => PersistentStateFlags::ARGUMENT_TY_IN_DEFINITION,
587-
CItemKind::Declaration => PersistentStateFlags::ARGUMENT_TY_IN_DECLARATION,
627+
CItemKind::ExportedFunction => PersistentStateFlags::ARGUMENT_TY_IN_DEFINITION,
628+
CItemKind::ImportedExtern => PersistentStateFlags::ARGUMENT_TY_IN_DECLARATION,
629+
// we could also deal with CItemKind::Callback,
630+
// but we bake an assumption from this function's call sites here.
631+
_ => bug!("cannot be called with CItemKind::{:?}", fn_mode),
588632
};
589633
Self::entry_point(p_flags)
590634
}
591635

592636
/// Get the proper visitor state for a given function's return type.
593637
fn return_from_fnmode(fn_mode: CItemKind) -> Self {
594638
let p_flags = match fn_mode {
595-
CItemKind::Definition => PersistentStateFlags::RETURN_TY_IN_DEFINITION,
596-
CItemKind::Declaration => PersistentStateFlags::RETURN_TY_IN_DECLARATION,
639+
CItemKind::ExportedFunction => PersistentStateFlags::RETURN_TY_IN_DEFINITION,
640+
CItemKind::ImportedExtern => PersistentStateFlags::RETURN_TY_IN_DECLARATION,
641+
// we could also deal with CItemKind::Callback,
642+
// but we bake an assumption from this function's call sites here.
643+
_ => bug!("cannot be called with CItemKind::{:?}", fn_mode),
597644
};
598645
Self::entry_point(p_flags)
599646
}
@@ -699,7 +746,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
699746
// - otherwise, treat the box itself correctly, and follow pointee safety logic
700747
// as described in the other `indirection_type` match branch.
701748
if state.is_in_defined_function()
702-
|| (state.is_in_fnptr() && matches!(self.base_fn_mode, CItemKind::Definition))
749+
|| (state.is_in_fnptr()
750+
&& matches!(self.base_fn_mode, CItemKind::ExportedFunction))
703751
{
704752
if inner_ty.is_sized(tcx, self.cx.typing_env()) {
705753
return FfiSafe;
@@ -1189,7 +1237,7 @@ impl<'tcx> ImproperCTypesLint {
11891237
// FIXME(ctypes): make a check_for_fnptr
11901238
let ffi_res = visitor.check_type(bridge_state, fn_ptr_ty);
11911239

1192-
self.process_ffi_result(cx, span, ffi_res, fn_mode);
1240+
self.process_ffi_result(cx, span, ffi_res, CItemKind::Callback);
11931241
}
11941242
}
11951243

@@ -1235,9 +1283,9 @@ impl<'tcx> ImproperCTypesLint {
12351283

12361284
fn check_foreign_static(&mut self, cx: &LateContext<'tcx>, id: hir::OwnerId, span: Span) {
12371285
let ty = cx.tcx.type_of(id).instantiate_identity();
1238-
let mut visitor = ImproperCTypesVisitor::new(cx, ty, CItemKind::Declaration);
1286+
let mut visitor = ImproperCTypesVisitor::new(cx, ty, CItemKind::ImportedExtern);
12391287
let ffi_res = visitor.check_type(VisitorState::static_var(), ty);
1240-
self.process_ffi_result(cx, span, ffi_res, CItemKind::Declaration);
1288+
self.process_ffi_result(cx, span, ffi_res, CItemKind::ImportedExtern);
12411289
}
12421290

12431291
/// Check if a function's argument types and result type are "ffi-safe".
@@ -1252,16 +1300,16 @@ impl<'tcx> ImproperCTypesLint {
12521300
let sig = cx.tcx.instantiate_bound_regions_with_erased(sig);
12531301

12541302
for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
1255-
let state = VisitorState::argument_from_fnmode(fn_mode);
1303+
let visit_state = VisitorState::argument_from_fnmode(fn_mode);
12561304
let mut visitor = ImproperCTypesVisitor::new(cx, *input_ty, fn_mode);
1257-
let ffi_res = visitor.check_type(state, *input_ty);
1305+
let ffi_res = visitor.check_type(visit_state, *input_ty);
12581306
self.process_ffi_result(cx, input_hir.span, ffi_res, fn_mode);
12591307
}
12601308

12611309
if let hir::FnRetTy::Return(ret_hir) = decl.output {
1262-
let state = VisitorState::return_from_fnmode(fn_mode);
1310+
let visit_state = VisitorState::return_from_fnmode(fn_mode);
12631311
let mut visitor = ImproperCTypesVisitor::new(cx, sig.output(), fn_mode);
1264-
let ffi_res = visitor.check_type(state, sig.output());
1312+
let ffi_res = visitor.check_type(visit_state, sig.output());
12651313
self.process_ffi_result(cx, ret_hir.span, ffi_res, fn_mode);
12661314
}
12671315
}
@@ -1338,12 +1386,14 @@ impl<'tcx> ImproperCTypesLint {
13381386
fn_mode: CItemKind,
13391387
) {
13401388
let lint = match fn_mode {
1341-
CItemKind::Declaration => IMPROPER_CTYPES,
1342-
CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS,
1389+
CItemKind::ImportedExtern => IMPROPER_CTYPES,
1390+
CItemKind::ExportedFunction => IMPROPER_C_FN_DEFINITIONS,
1391+
CItemKind::Callback => IMPROPER_C_CALLBACKS,
13431392
};
13441393
let desc = match fn_mode {
1345-
CItemKind::Declaration => "block",
1346-
CItemKind::Definition => "fn",
1394+
CItemKind::ImportedExtern => "`extern` block",
1395+
CItemKind::ExportedFunction => "`extern` fn",
1396+
CItemKind::Callback => "`extern` callback",
13471397
};
13481398
for reason in reasons.iter_mut() {
13491399
reason.span_note = if let ty::Adt(def, _) = reason.ty.kind()
@@ -1359,13 +1409,21 @@ impl<'tcx> ImproperCTypesLint {
13591409
}
13601410
}
13611411

1362-
/// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
1363-
/// `extern "C" { }` blocks):
1412+
/// IMPROPER_CTYPES checks items that are part of a header to a non-rust library
1413+
/// Namely, functions and static variables in `extern "<abi>" { }`,
1414+
/// if `<abi>` is external (e.g. "C").
1415+
///
1416+
/// `IMPROPER_C_CALLBACKS` checks for function pointers marked with an external ABI.
1417+
/// (fields of type `extern "<abi>" fn`, where e.g. `<abi>` is `C`)
1418+
/// These pointers are searched in all other items which contain types
1419+
/// (e.g.functions, struct definitions, etc)
1420+
///
1421+
/// `IMPROPER_C_FN_DEFINITIONS` checks rust-defined functions that are marked
1422+
/// to be used from the other side of a FFI boundary.
1423+
/// In other words, `extern "<abi>" fn` definitions and trait-method declarations.
1424+
/// This only matters if `<abi>` is external (e.g. `C`).
13641425
///
1365-
/// - `extern "<abi>" fn` definitions are checked in the same way as the
1366-
/// `ImproperCtypesDeclarations` visitor checks functions if `<abi>` is external (e.g. "C").
1367-
/// - All other items which contain types (e.g. other functions, struct definitions, etc) are
1368-
/// checked for extern fn-ptrs with external ABIs.
1426+
/// and now combinatorics for pointees
13691427
impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
13701428
fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, it: &hir::ForeignItem<'tcx>) {
13711429
let abi = cx.tcx.hir_get_foreign_abi(it.hir_id());
@@ -1376,11 +1434,16 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
13761434
// "the element rendered unsafe" because their unsafety doesn't affect
13771435
// their surroundings, and their type is often declared inline
13781436
if !abi.is_rustic_abi() {
1379-
self.check_foreign_fn(cx, CItemKind::Declaration, it.owner_id.def_id, sig.decl);
1437+
self.check_foreign_fn(
1438+
cx,
1439+
CItemKind::ImportedExtern,
1440+
it.owner_id.def_id,
1441+
sig.decl,
1442+
);
13801443
} else {
13811444
self.check_fn_for_external_abi_fnptr(
13821445
cx,
1383-
CItemKind::Declaration,
1446+
CItemKind::ImportedExtern,
13841447
it.owner_id.def_id,
13851448
sig.decl,
13861449
);
@@ -1403,7 +1466,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
14031466
VisitorState::static_var(),
14041467
ty,
14051468
cx.tcx.type_of(item.owner_id).instantiate_identity(),
1406-
CItemKind::Definition,
1469+
CItemKind::ExportedFunction, // TODO: for some reason, this is the value that reproduces old behaviour
14071470
);
14081471
}
14091472
// See `check_fn` for declarations, `check_foreign_items` for definitions in extern blocks
@@ -1437,7 +1500,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
14371500
VisitorState::static_var(),
14381501
field.ty,
14391502
cx.tcx.type_of(field.def_id).instantiate_identity(),
1440-
CItemKind::Definition,
1503+
CItemKind::ImportedExtern,
14411504
);
14421505
}
14431506

@@ -1462,9 +1525,9 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
14621525
// "the element rendered unsafe" because their unsafety doesn't affect
14631526
// their surroundings, and their type is often declared inline
14641527
if !abi.is_rustic_abi() {
1465-
self.check_foreign_fn(cx, CItemKind::Definition, id, decl);
1528+
self.check_foreign_fn(cx, CItemKind::ExportedFunction, id, decl);
14661529
} else {
1467-
self.check_fn_for_external_abi_fnptr(cx, CItemKind::Definition, id, decl);
1530+
self.check_fn_for_external_abi_fnptr(cx, CItemKind::ExportedFunction, id, decl);
14681531
}
14691532
}
14701533
}

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)