Auto merge of #146271 - niacdoial:improperctypes-refactor1, r=tgross35

lint ImproperCTypes: refactor linting architecture (part 1)

This is the first PR in an effort to split  rust-lang/rust#134697 into individually-mergeable parts.

This one focuses on properly packaging the lint and its tests, as well as properly separate the "linting" and "type-checking" code.

There is exactly one user-visible change: the safety of `Option<Box<FFISafePointee>>` is now the same in `extern` blocks and function definitions: it is safe.

r? `@tgross35` because you are already looking at the original
This commit is contained in:
bors 2025-09-07 04:17:27 +00:00
commit ebdf2abea4
44 changed files with 1143 additions and 1002 deletions

View file

@ -4022,6 +4022,7 @@ dependencies = [
name = "rustc_lint"
version = "0.0.0"
dependencies = [
"bitflags",
"rustc_abi",
"rustc_ast",
"rustc_ast_pretty",

View file

@ -5,6 +5,7 @@ edition = "2024"
[dependencies]
# tidy-alphabetical-start
bitflags = "2.4.1"
rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }

View file

@ -136,7 +136,6 @@ impl ClashingExternDeclarations {
ty::TypingEnv::non_body_analysis(tcx, this_fi.owner_id),
existing_decl_ty,
this_decl_ty,
types::CItemKind::Declaration,
) {
let orig = name_of_extern_decl(tcx, existing_did);
@ -214,10 +213,9 @@ fn structurally_same_type<'tcx>(
typing_env: ty::TypingEnv<'tcx>,
a: Ty<'tcx>,
b: Ty<'tcx>,
ckind: types::CItemKind,
) -> bool {
let mut seen_types = UnordSet::default();
let result = structurally_same_type_impl(&mut seen_types, tcx, typing_env, a, b, ckind);
let result = structurally_same_type_impl(&mut seen_types, tcx, typing_env, a, b);
if cfg!(debug_assertions) && result {
// Sanity-check: must have same ABI, size and alignment.
// `extern` blocks cannot be generic, so we'll always get a layout here.
@ -236,7 +234,6 @@ fn structurally_same_type_impl<'tcx>(
typing_env: ty::TypingEnv<'tcx>,
a: Ty<'tcx>,
b: Ty<'tcx>,
ckind: types::CItemKind,
) -> bool {
debug!("structurally_same_type_impl(tcx, a = {:?}, b = {:?})", a, b);
@ -307,7 +304,6 @@ fn structurally_same_type_impl<'tcx>(
typing_env,
tcx.type_of(a_did).instantiate(tcx, a_gen_args),
tcx.type_of(b_did).instantiate(tcx, b_gen_args),
ckind,
)
},
)
@ -315,25 +311,19 @@ fn structurally_same_type_impl<'tcx>(
(ty::Array(a_ty, a_len), ty::Array(b_ty, b_len)) => {
// For arrays, we also check the length.
a_len == b_len
&& structurally_same_type_impl(
seen_types, tcx, typing_env, *a_ty, *b_ty, ckind,
)
&& structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty)
}
(ty::Slice(a_ty), ty::Slice(b_ty)) => {
structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty, ckind)
structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty)
}
(ty::RawPtr(a_ty, a_mutbl), ty::RawPtr(b_ty, b_mutbl)) => {
a_mutbl == b_mutbl
&& structurally_same_type_impl(
seen_types, tcx, typing_env, *a_ty, *b_ty, ckind,
)
&& structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty)
}
(ty::Ref(_a_region, a_ty, a_mut), ty::Ref(_b_region, b_ty, b_mut)) => {
// For structural sameness, we don't need the region to be same.
a_mut == b_mut
&& structurally_same_type_impl(
seen_types, tcx, typing_env, *a_ty, *b_ty, ckind,
)
&& structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty)
}
(ty::FnDef(..), ty::FnDef(..)) => {
let a_poly_sig = a.fn_sig(tcx);
@ -347,7 +337,7 @@ fn structurally_same_type_impl<'tcx>(
(a_sig.abi, a_sig.safety, a_sig.c_variadic)
== (b_sig.abi, b_sig.safety, b_sig.c_variadic)
&& a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
structurally_same_type_impl(seen_types, tcx, typing_env, *a, *b, ckind)
structurally_same_type_impl(seen_types, tcx, typing_env, *a, *b)
})
&& structurally_same_type_impl(
seen_types,
@ -355,7 +345,6 @@ fn structurally_same_type_impl<'tcx>(
typing_env,
a_sig.output(),
b_sig.output(),
ckind,
)
}
(ty::Tuple(..), ty::Tuple(..)) => {
@ -383,14 +372,14 @@ fn structurally_same_type_impl<'tcx>(
// An Adt and a primitive or pointer type. This can be FFI-safe if non-null
// enum layout optimisation is being applied.
(ty::Adt(..) | ty::Pat(..), _) if is_primitive_or_pointer(b) => {
if let Some(a_inner) = types::repr_nullable_ptr(tcx, typing_env, a, ckind) {
if let Some(a_inner) = types::repr_nullable_ptr(tcx, typing_env, a) {
a_inner == b
} else {
false
}
}
(_, ty::Adt(..) | ty::Pat(..)) if is_primitive_or_pointer(a) => {
if let Some(b_inner) = types::repr_nullable_ptr(tcx, typing_env, b, ckind) {
if let Some(b_inner) = types::repr_nullable_ptr(tcx, typing_env, b) {
b_inner == a
} else {
false

View file

@ -194,8 +194,7 @@ late_lint_methods!(
DefaultCouldBeDerived: DefaultCouldBeDerived::default(),
DerefIntoDynSupertrait: DerefIntoDynSupertrait,
DropForgetUseless: DropForgetUseless,
ImproperCTypesDeclarations: ImproperCTypesDeclarations,
ImproperCTypesDefinitions: ImproperCTypesDefinitions,
ImproperCTypesLint: ImproperCTypesLint,
InvalidFromUtf8: InvalidFromUtf8,
VariantSizeDifferences: VariantSizeDifferences,
PathStatements: PathStatements,

View file

@ -1,35 +1,28 @@
use std::iter;
use std::ops::ControlFlow;
use rustc_abi::{BackendRepr, TagEncoding, VariantIdx, Variants, WrappingRange};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::DiagMessage;
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::{AmbigArg, Expr, ExprKind, HirId, LangItem};
use rustc_abi::{BackendRepr, TagEncoding, Variants, WrappingRange};
use rustc_hir::{Expr, ExprKind, HirId, LangItem};
use rustc_middle::bug;
use rustc_middle::ty::layout::{LayoutOf, SizeSkeleton};
use rustc_middle::ty::{
self, Adt, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
TypeVisitableExt,
};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
use rustc_span::def_id::LocalDefId;
use rustc_span::{Span, Symbol, sym};
use tracing::debug;
use {rustc_ast as ast, rustc_hir as hir};
mod improper_ctypes;
mod improper_ctypes; // these filed do the implementation for ImproperCTypesDefinitions,ImproperCTypesDeclarations
pub(crate) use improper_ctypes::ImproperCTypesLint;
use crate::lints::{
AmbiguousWidePointerComparisons, AmbiguousWidePointerComparisonsAddrMetadataSuggestion,
AmbiguousWidePointerComparisonsAddrSuggestion, AmbiguousWidePointerComparisonsCastSuggestion,
AmbiguousWidePointerComparisonsExpectSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons,
AtomicOrderingStore, InvalidAtomicOrderingDiag, InvalidNanComparisons,
InvalidNanComparisonsSuggestion, UnpredictableFunctionPointerComparisons,
UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons, UsesPowerAlignment,
UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons,
VariantSizeDifferencesDiag,
};
use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
use crate::{LateContext, LateLintPass, LintContext};
mod literal;
@ -690,144 +683,6 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
}
}
declare_lint! {
/// The `improper_ctypes` lint detects incorrect use of types in foreign
/// modules.
///
/// ### Example
///
/// ```rust
/// unsafe extern "C" {
/// static STATIC: String;
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// The compiler has several checks to verify that types used in `extern`
/// blocks are safe and follow certain rules to ensure proper
/// compatibility with the foreign interfaces. This lint is issued when it
/// detects a probable mistake in a definition. The lint usually should
/// provide a description of the issue, along with possibly a hint on how
/// to resolve it.
IMPROPER_CTYPES,
Warn,
"proper use of libc types in foreign modules"
}
declare_lint_pass!(ImproperCTypesDeclarations => [IMPROPER_CTYPES]);
declare_lint! {
/// The `improper_ctypes_definitions` lint detects incorrect use of
/// [`extern` function] definitions.
///
/// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
///
/// ### Example
///
/// ```rust
/// # #![allow(unused)]
/// pub extern "C" fn str_type(p: &str) { }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// There are many parameter and return types that may be specified in an
/// `extern` function that are not compatible with the given ABI. This
/// lint is an alert that these types should not be used. The lint usually
/// should provide a description of the issue, along with possibly a hint
/// on how to resolve it.
IMPROPER_CTYPES_DEFINITIONS,
Warn,
"proper use of libc types in foreign item definitions"
}
declare_lint! {
/// The `uses_power_alignment` lint detects specific `repr(C)`
/// aggregates on AIX.
/// In its platform C ABI, AIX uses the "power" (as in PowerPC) alignment
/// rule (detailed in https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes#alignment),
/// which can also be set for XLC by `#pragma align(power)` or
/// `-qalign=power`. Aggregates with a floating-point type as the
/// recursively first field (as in "at offset 0") modify the layout of
/// *subsequent* fields of the associated structs to use an alignment value
/// where the floating-point type is aligned on a 4-byte boundary.
///
/// Effectively, subsequent floating-point fields act as-if they are `repr(packed(4))`. This
/// would be unsound to do in a `repr(C)` type without all the restrictions that come with
/// `repr(packed)`. Rust instead chooses a layout that maintains soundness of Rust code, at the
/// expense of incompatibility with C code.
///
/// ### Example
///
/// ```rust,ignore (fails on non-powerpc64-ibm-aix)
/// #[repr(C)]
/// pub struct Floats {
/// a: f64,
/// b: u8,
/// c: f64,
/// }
/// ```
///
/// This will produce:
///
/// ```text
/// warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
/// --> <source>:5:3
/// |
/// 5 | c: f64,
/// | ^^^^^^
/// |
/// = note: `#[warn(uses_power_alignment)]` on by default
/// ```
///
/// ### Explanation
///
/// The power alignment rule specifies that the above struct has the
/// following alignment:
/// - offset_of!(Floats, a) == 0
/// - offset_of!(Floats, b) == 8
/// - offset_of!(Floats, c) == 12
///
/// However, Rust currently aligns `c` at `offset_of!(Floats, c) == 16`.
/// Using offset 12 would be unsound since `f64` generally must be 8-aligned on this target.
/// Thus, a warning is produced for the above struct.
USES_POWER_ALIGNMENT,
Warn,
"Structs do not follow the power alignment rule under repr(C)"
}
declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS, USES_POWER_ALIGNMENT]);
#[derive(Clone, Copy)]
pub(crate) enum CItemKind {
Declaration,
Definition,
}
struct ImproperCTypesVisitor<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
mode: CItemKind,
}
/// Accumulator for recursive ffi type checking
struct CTypesVisitorState<'tcx> {
cache: FxHashSet<Ty<'tcx>>,
/// The original type being checked, before we recursed
/// to any other types it contains.
base_ty: Ty<'tcx>,
}
enum FfiResult<'tcx> {
FfiSafe,
FfiPhantom(Ty<'tcx>),
FfiUnsafe { ty: Ty<'tcx>, reason: DiagMessage, help: Option<DiagMessage> },
}
pub(crate) fn nonnull_optimization_guaranteed<'tcx>(
tcx: TyCtxt<'tcx>,
def: ty::AdtDef<'tcx>,
@ -855,14 +710,13 @@ fn ty_is_known_nonnull<'tcx>(
tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
ty: Ty<'tcx>,
mode: CItemKind,
) -> bool {
let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
match ty.kind() {
ty::FnPtr(..) => true,
ty::Ref(..) => true,
ty::Adt(def, _) if def.is_box() && matches!(mode, CItemKind::Definition) => true,
ty::Adt(def, _) if def.is_box() => true,
ty::Adt(def, args) if def.repr().transparent() && !def.is_union() => {
let marked_non_null = nonnull_optimization_guaranteed(tcx, *def);
@ -878,10 +732,10 @@ fn ty_is_known_nonnull<'tcx>(
def.variants()
.iter()
.filter_map(|variant| transparent_newtype_field(tcx, variant))
.any(|field| ty_is_known_nonnull(tcx, typing_env, field.ty(tcx, args), mode))
.any(|field| ty_is_known_nonnull(tcx, typing_env, field.ty(tcx, args)))
}
ty::Pat(base, pat) => {
ty_is_known_nonnull(tcx, typing_env, *base, mode)
ty_is_known_nonnull(tcx, typing_env, *base)
|| pat_ty_is_known_nonnull(tcx, typing_env, *pat)
}
_ => false,
@ -992,7 +846,6 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
ty: Ty<'tcx>,
ckind: CItemKind,
) -> Option<Ty<'tcx>> {
debug!("is_repr_nullable_ptr(tcx, ty = {:?})", ty);
match ty.kind() {
@ -1017,7 +870,7 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
_ => return None,
};
if !ty_is_known_nonnull(tcx, typing_env, field_ty, ckind) {
if !ty_is_known_nonnull(tcx, typing_env, field_ty) {
return None;
}
@ -1076,710 +929,6 @@ fn get_nullable_type_from_pat<'tcx>(
}
}
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
/// Check if the type is array and emit an unsafe type lint.
fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
if let ty::Array(..) = ty.kind() {
self.emit_ffi_unsafe_type_lint(
ty,
sp,
fluent::lint_improper_ctypes_array_reason,
Some(fluent::lint_improper_ctypes_array_help),
);
true
} else {
false
}
}
/// Checks if the given field's type is "ffi-safe".
fn check_field_type_for_ffi(
&self,
acc: &mut CTypesVisitorState<'tcx>,
field: &ty::FieldDef,
args: GenericArgsRef<'tcx>,
) -> FfiResult<'tcx> {
let field_ty = field.ty(self.cx.tcx, args);
let field_ty = self
.cx
.tcx
.try_normalize_erasing_regions(self.cx.typing_env(), field_ty)
.unwrap_or(field_ty);
self.check_type_for_ffi(acc, field_ty)
}
/// Checks if the given `VariantDef`'s field types are "ffi-safe".
fn check_variant_for_ffi(
&self,
acc: &mut CTypesVisitorState<'tcx>,
ty: Ty<'tcx>,
def: ty::AdtDef<'tcx>,
variant: &ty::VariantDef,
args: GenericArgsRef<'tcx>,
) -> FfiResult<'tcx> {
use FfiResult::*;
let transparent_with_all_zst_fields = if def.repr().transparent() {
if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
// Transparent newtypes have at most one non-ZST field which needs to be checked..
match self.check_field_type_for_ffi(acc, field, args) {
FfiUnsafe { ty, .. } if ty.is_unit() => (),
r => return r,
}
false
} else {
// ..or have only ZST fields, which is FFI-unsafe (unless those fields are all
// `PhantomData`).
true
}
} else {
false
};
// We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
let mut all_phantom = !variant.fields.is_empty();
for field in &variant.fields {
all_phantom &= match self.check_field_type_for_ffi(acc, field, args) {
FfiSafe => false,
// `()` fields are FFI-safe!
FfiUnsafe { ty, .. } if ty.is_unit() => false,
FfiPhantom(..) => true,
r @ FfiUnsafe { .. } => return r,
}
}
if all_phantom {
FfiPhantom(ty)
} else if transparent_with_all_zst_fields {
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
} else {
FfiSafe
}
}
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
/// representation which can be exported to C code).
fn check_type_for_ffi(
&self,
acc: &mut CTypesVisitorState<'tcx>,
ty: Ty<'tcx>,
) -> FfiResult<'tcx> {
use FfiResult::*;
let tcx = self.cx.tcx;
// Protect against infinite recursion, for example
// `struct S(*mut S);`.
// FIXME: A recursion limit is necessary as well, for irregular
// recursive types.
if !acc.cache.insert(ty) {
return FfiSafe;
}
match *ty.kind() {
ty::Adt(def, args) => {
if let Some(boxed) = ty.boxed_ty()
&& matches!(self.mode, CItemKind::Definition)
{
if boxed.is_sized(tcx, self.cx.typing_env()) {
return FfiSafe;
} else {
return FfiUnsafe {
ty,
reason: fluent::lint_improper_ctypes_box,
help: None,
};
}
}
if def.is_phantom_data() {
return FfiPhantom(ty);
}
match def.adt_kind() {
AdtKind::Struct | AdtKind::Union => {
if let Some(sym::cstring_type | sym::cstr_type) =
tcx.get_diagnostic_name(def.did())
&& !acc.base_ty.is_mutable_ptr()
{
return FfiUnsafe {
ty,
reason: fluent::lint_improper_ctypes_cstr_reason,
help: Some(fluent::lint_improper_ctypes_cstr_help),
};
}
if !def.repr().c() && !def.repr().transparent() {
return FfiUnsafe {
ty,
reason: if def.is_struct() {
fluent::lint_improper_ctypes_struct_layout_reason
} else {
fluent::lint_improper_ctypes_union_layout_reason
},
help: if def.is_struct() {
Some(fluent::lint_improper_ctypes_struct_layout_help)
} else {
Some(fluent::lint_improper_ctypes_union_layout_help)
},
};
}
if def.non_enum_variant().field_list_has_applicable_non_exhaustive() {
return FfiUnsafe {
ty,
reason: if def.is_struct() {
fluent::lint_improper_ctypes_struct_non_exhaustive
} else {
fluent::lint_improper_ctypes_union_non_exhaustive
},
help: None,
};
}
if def.non_enum_variant().fields.is_empty() {
return FfiUnsafe {
ty,
reason: if def.is_struct() {
fluent::lint_improper_ctypes_struct_fieldless_reason
} else {
fluent::lint_improper_ctypes_union_fieldless_reason
},
help: if def.is_struct() {
Some(fluent::lint_improper_ctypes_struct_fieldless_help)
} else {
Some(fluent::lint_improper_ctypes_union_fieldless_help)
},
};
}
self.check_variant_for_ffi(acc, ty, def, def.non_enum_variant(), args)
}
AdtKind::Enum => {
if def.variants().is_empty() {
// Empty enums are okay... although sort of useless.
return FfiSafe;
}
// Check for a repr() attribute to specify the size of the
// discriminant.
if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none()
{
// Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>`
if let Some(ty) =
repr_nullable_ptr(self.cx.tcx, self.cx.typing_env(), ty, self.mode)
{
return self.check_type_for_ffi(acc, ty);
}
return FfiUnsafe {
ty,
reason: fluent::lint_improper_ctypes_enum_repr_reason,
help: Some(fluent::lint_improper_ctypes_enum_repr_help),
};
}
use improper_ctypes::check_non_exhaustive_variant;
let non_exhaustive = def.variant_list_has_applicable_non_exhaustive();
// Check the contained variants.
let ret = def.variants().iter().try_for_each(|variant| {
check_non_exhaustive_variant(non_exhaustive, variant)
.map_break(|reason| FfiUnsafe { ty, reason, help: None })?;
match self.check_variant_for_ffi(acc, ty, def, variant, args) {
FfiSafe => ControlFlow::Continue(()),
r => ControlFlow::Break(r),
}
});
if let ControlFlow::Break(result) = ret {
return result;
}
FfiSafe
}
}
}
ty::Char => FfiUnsafe {
ty,
reason: fluent::lint_improper_ctypes_char_reason,
help: Some(fluent::lint_improper_ctypes_char_help),
},
// It's just extra invariants on the type that you need to uphold,
// but only the base type is relevant for being representable in FFI.
ty::Pat(base, ..) => self.check_type_for_ffi(acc, base),
// Primitive types with a stable representation.
ty::Bool | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Never => FfiSafe,
ty::Slice(_) => FfiUnsafe {
ty,
reason: fluent::lint_improper_ctypes_slice_reason,
help: Some(fluent::lint_improper_ctypes_slice_help),
},
ty::Dynamic(..) => {
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_dyn, help: None }
}
ty::Str => FfiUnsafe {
ty,
reason: fluent::lint_improper_ctypes_str_reason,
help: Some(fluent::lint_improper_ctypes_str_help),
},
ty::Tuple(..) => FfiUnsafe {
ty,
reason: fluent::lint_improper_ctypes_tuple_reason,
help: Some(fluent::lint_improper_ctypes_tuple_help),
},
ty::RawPtr(ty, _) | ty::Ref(_, ty, _)
if {
matches!(self.mode, CItemKind::Definition)
&& ty.is_sized(self.cx.tcx, self.cx.typing_env())
} =>
{
FfiSafe
}
ty::RawPtr(ty, _)
if match ty.kind() {
ty::Tuple(tuple) => tuple.is_empty(),
_ => false,
} =>
{
FfiSafe
}
ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => self.check_type_for_ffi(acc, ty),
ty::Array(inner_ty, _) => self.check_type_for_ffi(acc, inner_ty),
ty::FnPtr(sig_tys, hdr) => {
let sig = sig_tys.with(hdr);
if sig.abi().is_rustic_abi() {
return FfiUnsafe {
ty,
reason: fluent::lint_improper_ctypes_fnptr_reason,
help: Some(fluent::lint_improper_ctypes_fnptr_help),
};
}
let sig = tcx.instantiate_bound_regions_with_erased(sig);
for arg in sig.inputs() {
match self.check_type_for_ffi(acc, *arg) {
FfiSafe => {}
r => return r,
}
}
let ret_ty = sig.output();
if ret_ty.is_unit() {
return FfiSafe;
}
self.check_type_for_ffi(acc, ret_ty)
}
ty::Foreign(..) => FfiSafe,
// While opaque types are checked for earlier, if a projection in a struct field
// normalizes to an opaque type, then it will reach this branch.
ty::Alias(ty::Opaque, ..) => {
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_opaque, help: None }
}
// `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
// so they are currently ignored for the purposes of this lint.
ty::Param(..) | ty::Alias(ty::Projection | ty::Inherent, ..)
if matches!(self.mode, CItemKind::Definition) =>
{
FfiSafe
}
ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"),
ty::Param(..)
| ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..)
| ty::Infer(..)
| ty::Bound(..)
| ty::Error(_)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..)
| ty::Placeholder(..)
| ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty),
}
}
fn emit_ffi_unsafe_type_lint(
&mut self,
ty: Ty<'tcx>,
sp: Span,
note: DiagMessage,
help: Option<DiagMessage>,
) {
let lint = match self.mode {
CItemKind::Declaration => IMPROPER_CTYPES,
CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS,
};
let desc = match self.mode {
CItemKind::Declaration => "block",
CItemKind::Definition => "fn",
};
let span_note = if let ty::Adt(def, _) = ty.kind()
&& let Some(sp) = self.cx.tcx.hir_span_if_local(def.did())
{
Some(sp)
} else {
None
};
self.cx.emit_span_lint(
lint,
sp,
ImproperCTypes { ty, desc, label: sp, help, note, span_note },
);
}
fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
struct ProhibitOpaqueTypes;
impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for ProhibitOpaqueTypes {
type Result = ControlFlow<Ty<'tcx>>;
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
if !ty.has_opaque_types() {
return ControlFlow::Continue(());
}
if let ty::Alias(ty::Opaque, ..) = ty.kind() {
ControlFlow::Break(ty)
} else {
ty.super_visit_with(self)
}
}
}
if let Some(ty) = self
.cx
.tcx
.try_normalize_erasing_regions(self.cx.typing_env(), ty)
.unwrap_or(ty)
.visit_with(&mut ProhibitOpaqueTypes)
.break_value()
{
self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint_improper_ctypes_opaque, None);
true
} else {
false
}
}
fn check_type_for_ffi_and_report_errors(
&mut self,
sp: Span,
ty: Ty<'tcx>,
is_static: bool,
is_return_type: bool,
) {
if self.check_for_opaque_ty(sp, ty) {
// We've already emitted an error due to an opaque type.
return;
}
let ty = self.cx.tcx.try_normalize_erasing_regions(self.cx.typing_env(), ty).unwrap_or(ty);
// C doesn't really support passing arrays by value - the only way to pass an array by value
// is through a struct. So, first test that the top level isn't an array, and then
// recursively check the types inside.
if !is_static && self.check_for_array_ty(sp, ty) {
return;
}
// Don't report FFI errors for unit return types. This check exists here, and not in
// the caller (where it would make more sense) so that normalization has definitely
// happened.
if is_return_type && ty.is_unit() {
return;
}
let mut acc = CTypesVisitorState { cache: FxHashSet::default(), base_ty: ty };
match self.check_type_for_ffi(&mut acc, ty) {
FfiResult::FfiSafe => {}
FfiResult::FfiPhantom(ty) => {
self.emit_ffi_unsafe_type_lint(
ty,
sp,
fluent::lint_improper_ctypes_only_phantomdata,
None,
);
}
FfiResult::FfiUnsafe { ty, reason, help } => {
self.emit_ffi_unsafe_type_lint(ty, sp, reason, help);
}
}
}
/// Check if a function's argument types and result type are "ffi-safe".
///
/// For a external ABI function, argument types and the result type are walked to find fn-ptr
/// types that have external ABIs, as these still need checked.
fn check_fn(&mut self, def_id: LocalDefId, decl: &'tcx hir::FnDecl<'_>) {
let sig = self.cx.tcx.fn_sig(def_id).instantiate_identity();
let sig = self.cx.tcx.instantiate_bound_regions_with_erased(sig);
for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
for (fn_ptr_ty, span) in self.find_fn_ptr_ty_with_external_abi(input_hir, *input_ty) {
self.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, false, false);
}
}
if let hir::FnRetTy::Return(ret_hir) = decl.output {
for (fn_ptr_ty, span) in self.find_fn_ptr_ty_with_external_abi(ret_hir, sig.output()) {
self.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, false, true);
}
}
}
/// Check if a function's argument types and result type are "ffi-safe".
fn check_foreign_fn(&mut self, def_id: LocalDefId, decl: &'tcx hir::FnDecl<'_>) {
let sig = self.cx.tcx.fn_sig(def_id).instantiate_identity();
let sig = self.cx.tcx.instantiate_bound_regions_with_erased(sig);
for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
self.check_type_for_ffi_and_report_errors(input_hir.span, *input_ty, false, false);
}
if let hir::FnRetTy::Return(ret_hir) = decl.output {
self.check_type_for_ffi_and_report_errors(ret_hir.span, sig.output(), false, true);
}
}
fn check_foreign_static(&mut self, id: hir::OwnerId, span: Span) {
let ty = self.cx.tcx.type_of(id).instantiate_identity();
self.check_type_for_ffi_and_report_errors(span, ty, true, false);
}
/// Find any fn-ptr types with external ABIs in `ty`.
///
/// For example, `Option<extern "C" fn()>` returns `extern "C" fn()`
fn find_fn_ptr_ty_with_external_abi(
&self,
hir_ty: &hir::Ty<'tcx>,
ty: Ty<'tcx>,
) -> Vec<(Ty<'tcx>, Span)> {
struct FnPtrFinder<'tcx> {
spans: Vec<Span>,
tys: Vec<Ty<'tcx>>,
}
impl<'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'tcx> {
fn visit_ty(&mut self, ty: &'_ hir::Ty<'_, AmbigArg>) {
debug!(?ty);
if let hir::TyKind::FnPtr(hir::FnPtrTy { abi, .. }) = ty.kind
&& !abi.is_rustic_abi()
{
self.spans.push(ty.span);
}
hir::intravisit::walk_ty(self, ty)
}
}
impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for FnPtrFinder<'tcx> {
type Result = ();
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
if let ty::FnPtr(_, hdr) = ty.kind()
&& !hdr.abi.is_rustic_abi()
{
self.tys.push(ty);
}
ty.super_visit_with(self)
}
}
let mut visitor = FnPtrFinder { spans: Vec::new(), tys: Vec::new() };
ty.visit_with(&mut visitor);
visitor.visit_ty_unambig(hir_ty);
iter::zip(visitor.tys.drain(..), visitor.spans.drain(..)).collect()
}
}
impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations {
fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, it: &hir::ForeignItem<'tcx>) {
let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Declaration };
let abi = cx.tcx.hir_get_foreign_abi(it.hir_id());
match it.kind {
hir::ForeignItemKind::Fn(sig, _, _) => {
if abi.is_rustic_abi() {
vis.check_fn(it.owner_id.def_id, sig.decl)
} else {
vis.check_foreign_fn(it.owner_id.def_id, sig.decl);
}
}
hir::ForeignItemKind::Static(ty, _, _) if !abi.is_rustic_abi() => {
vis.check_foreign_static(it.owner_id, ty.span);
}
hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (),
}
}
}
impl ImproperCTypesDefinitions {
fn check_ty_maybe_containing_foreign_fnptr<'tcx>(
&mut self,
cx: &LateContext<'tcx>,
hir_ty: &'tcx hir::Ty<'_>,
ty: Ty<'tcx>,
) {
let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Definition };
for (fn_ptr_ty, span) in vis.find_fn_ptr_ty_with_external_abi(hir_ty, ty) {
vis.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, true, false);
}
}
fn check_arg_for_power_alignment<'tcx>(
&mut self,
cx: &LateContext<'tcx>,
ty: Ty<'tcx>,
) -> bool {
assert!(cx.tcx.sess.target.os == "aix");
// Structs (under repr(C)) follow the power alignment rule if:
// - the first field of the struct is a floating-point type that
// is greater than 4-bytes, or
// - the first field of the struct is an aggregate whose
// recursively first field is a floating-point type greater than
// 4 bytes.
if ty.is_floating_point() && ty.primitive_size(cx.tcx).bytes() > 4 {
return true;
} else if let Adt(adt_def, _) = ty.kind()
&& adt_def.is_struct()
&& adt_def.repr().c()
&& !adt_def.repr().packed()
&& adt_def.repr().align.is_none()
{
let struct_variant = adt_def.variant(VariantIdx::ZERO);
// Within a nested struct, all fields are examined to correctly
// report if any fields after the nested struct within the
// original struct are misaligned.
for struct_field in &struct_variant.fields {
let field_ty = cx.tcx.type_of(struct_field.did).instantiate_identity();
if self.check_arg_for_power_alignment(cx, field_ty) {
return true;
}
}
}
return false;
}
fn check_struct_for_power_alignment<'tcx>(
&mut self,
cx: &LateContext<'tcx>,
item: &'tcx hir::Item<'tcx>,
) {
let adt_def = cx.tcx.adt_def(item.owner_id.to_def_id());
// repr(C) structs also with packed or aligned representation
// should be ignored.
if adt_def.repr().c()
&& !adt_def.repr().packed()
&& adt_def.repr().align.is_none()
&& cx.tcx.sess.target.os == "aix"
&& !adt_def.all_fields().next().is_none()
{
let struct_variant_data = item.expect_struct().2;
for field_def in struct_variant_data.fields().iter().skip(1) {
// Struct fields (after the first field) are checked for the
// power alignment rule, as fields after the first are likely
// to be the fields that are misaligned.
let def_id = field_def.def_id;
let ty = cx.tcx.type_of(def_id).instantiate_identity();
if self.check_arg_for_power_alignment(cx, ty) {
cx.emit_span_lint(USES_POWER_ALIGNMENT, field_def.span, UsesPowerAlignment);
}
}
}
}
}
/// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
/// `extern "C" { }` blocks):
///
/// - `extern "<abi>" fn` definitions are checked in the same way as the
/// `ImproperCtypesDeclarations` visitor checks functions if `<abi>` is external (e.g. "C").
/// - All other items which contain types (e.g. other functions, struct definitions, etc) are
/// checked for extern fn-ptrs with external ABIs.
impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
match item.kind {
hir::ItemKind::Static(_, _, ty, _)
| hir::ItemKind::Const(_, _, ty, _)
| hir::ItemKind::TyAlias(_, _, ty) => {
self.check_ty_maybe_containing_foreign_fnptr(
cx,
ty,
cx.tcx.type_of(item.owner_id).instantiate_identity(),
);
}
// See `check_fn`..
hir::ItemKind::Fn { .. } => {}
// Structs are checked based on if they follow the power alignment
// rule (under repr(C)).
hir::ItemKind::Struct(..) => {
self.check_struct_for_power_alignment(cx, item);
}
// See `check_field_def`..
hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {}
// Doesn't define something that can contain a external type to be checked.
hir::ItemKind::Impl(..)
| hir::ItemKind::TraitAlias(..)
| hir::ItemKind::Trait(..)
| hir::ItemKind::GlobalAsm { .. }
| hir::ItemKind::ForeignMod { .. }
| hir::ItemKind::Mod(..)
| hir::ItemKind::Macro(..)
| hir::ItemKind::Use(..)
| hir::ItemKind::ExternCrate(..) => {}
}
}
fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::FieldDef<'tcx>) {
self.check_ty_maybe_containing_foreign_fnptr(
cx,
field.ty,
cx.tcx.type_of(field.def_id).instantiate_identity(),
);
}
fn check_fn(
&mut self,
cx: &LateContext<'tcx>,
kind: hir::intravisit::FnKind<'tcx>,
decl: &'tcx hir::FnDecl<'_>,
_: &'tcx hir::Body<'_>,
_: Span,
id: LocalDefId,
) {
use hir::intravisit::FnKind;
let abi = match kind {
FnKind::ItemFn(_, _, header, ..) => header.abi,
FnKind::Method(_, sig, ..) => sig.header.abi,
_ => return,
};
let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Definition };
if abi.is_rustic_abi() {
vis.check_fn(id, decl);
} else {
vis.check_foreign_fn(id, decl);
}
}
}
declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]);
impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
error: `extern` fn uses type `NotSafe`, which is not FFI-safe
--> $DIR/lint-ctypes-113436-1.rs:22:22
--> $DIR/lint-113436-1.rs:22:22
|
LL | extern "C" fn bar(x: Bar) -> Bar {
| ^^^ not FFI-safe
@ -7,18 +7,18 @@ LL | extern "C" fn bar(x: Bar) -> Bar {
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
note: the type is defined here
--> $DIR/lint-ctypes-113436-1.rs:13:1
--> $DIR/lint-113436-1.rs:13:1
|
LL | struct NotSafe(u32);
| ^^^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/lint-ctypes-113436-1.rs:1:9
--> $DIR/lint-113436-1.rs:1:9
|
LL | #![deny(improper_ctypes_definitions)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `extern` fn uses type `NotSafe`, which is not FFI-safe
--> $DIR/lint-ctypes-113436-1.rs:22:30
--> $DIR/lint-113436-1.rs:22:30
|
LL | extern "C" fn bar(x: Bar) -> Bar {
| ^^^ not FFI-safe
@ -26,7 +26,7 @@ LL | extern "C" fn bar(x: Bar) -> Bar {
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
note: the type is defined here
--> $DIR/lint-ctypes-113436-1.rs:13:1
--> $DIR/lint-113436-1.rs:13:1
|
LL | struct NotSafe(u32);
| ^^^^^^^^^^^^^^

View file

@ -1,12 +1,12 @@
error: `extern` block uses type `Qux`, which is not FFI-safe
--> $DIR/lint-ctypes-73249-2.rs:27:21
--> $DIR/lint-73249-2.rs:27:21
|
LL | fn lint_me() -> A<()>;
| ^^^^^ not FFI-safe
|
= note: opaque types have no C equivalent
note: the lint level is defined here
--> $DIR/lint-ctypes-73249-2.rs:2:9
--> $DIR/lint-73249-2.rs:2:9
|
LL | #![deny(improper_ctypes)]
| ^^^^^^^^^^^^^^^

View file

@ -1,12 +1,12 @@
error: `extern` block uses type `Qux`, which is not FFI-safe
--> $DIR/lint-ctypes-73249-5.rs:21:25
--> $DIR/lint-73249-3.rs:21:25
|
LL | pub fn lint_me() -> A;
| ^ not FFI-safe
|
= note: opaque types have no C equivalent
note: the lint level is defined here
--> $DIR/lint-ctypes-73249-5.rs:2:9
--> $DIR/lint-73249-3.rs:2:9
|
LL | #![deny(improper_ctypes)]
| ^^^^^^^^^^^^^^^

View file

@ -1,12 +1,12 @@
error: `extern` block uses type `Qux`, which is not FFI-safe
--> $DIR/lint-ctypes-73249-3.rs:21:25
--> $DIR/lint-73249-5.rs:21:25
|
LL | pub fn lint_me() -> A;
| ^ not FFI-safe
|
= note: opaque types have no C equivalent
note: the lint level is defined here
--> $DIR/lint-ctypes-73249-3.rs:2:9
--> $DIR/lint-73249-5.rs:2:9
|
LL | #![deny(improper_ctypes)]
| ^^^^^^^^^^^^^^^

View file

@ -1,12 +1,12 @@
error: `extern` block uses type `Qux`, which is not FFI-safe
--> $DIR/lint-ctypes-73251-1.rs:24:21
--> $DIR/lint-73251-1.rs:24:21
|
LL | fn lint_me() -> <u32 as Foo>::Assoc;
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: opaque types have no C equivalent
note: the lint level is defined here
--> $DIR/lint-ctypes-73251-1.rs:2:9
--> $DIR/lint-73251-1.rs:2:9
|
LL | #![deny(improper_ctypes)]
| ^^^^^^^^^^^^^^^

View file

@ -1,12 +1,12 @@
error: `extern` block uses type `AliasA`, which is not FFI-safe
--> $DIR/lint-ctypes-73251-2.rs:38:21
--> $DIR/lint-73251-2.rs:38:21
|
LL | fn lint_me() -> <AliasB as TraitB>::Assoc;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: opaque types have no C equivalent
note: the lint level is defined here
--> $DIR/lint-ctypes-73251-2.rs:2:9
--> $DIR/lint-73251-2.rs:2:9
|
LL | #![deny(improper_ctypes)]
| ^^^^^^^^^^^^^^^

View file

@ -1,5 +1,5 @@
error: `extern` fn uses type `[u8]`, which is not FFI-safe
--> $DIR/lint-ctypes-94223.rs:4:15
--> $DIR/lint-94223.rs:4:15
|
LL | pub fn bad(f: extern "C" fn([u8])) {}
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -7,13 +7,13 @@ LL | pub fn bad(f: extern "C" fn([u8])) {}
= help: consider using a raw pointer instead
= note: slices have no C equivalent
note: the lint level is defined here
--> $DIR/lint-ctypes-94223.rs:2:9
--> $DIR/lint-94223.rs:2:9
|
LL | #![deny(improper_ctypes_definitions)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `extern` fn uses type `[u8]`, which is not FFI-safe
--> $DIR/lint-ctypes-94223.rs:7:28
--> $DIR/lint-94223.rs:7:28
|
LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {}
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -22,7 +22,7 @@ LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {}
= note: slices have no C equivalent
error: `extern` fn uses type `[u8]`, which is not FFI-safe
--> $DIR/lint-ctypes-94223.rs:7:49
--> $DIR/lint-94223.rs:7:49
|
LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {}
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -31,7 +31,7 @@ LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {}
= note: slices have no C equivalent
error: `extern` fn uses type `[u8]`, which is not FFI-safe
--> $DIR/lint-ctypes-94223.rs:11:18
--> $DIR/lint-94223.rs:11:18
|
LL | struct BadStruct(extern "C" fn([u8]));
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -40,7 +40,7 @@ LL | struct BadStruct(extern "C" fn([u8]));
= note: slices have no C equivalent
error: `extern` fn uses type `[u8]`, which is not FFI-safe
--> $DIR/lint-ctypes-94223.rs:15:7
--> $DIR/lint-94223.rs:15:7
|
LL | A(extern "C" fn([u8])),
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -49,7 +49,7 @@ LL | A(extern "C" fn([u8])),
= note: slices have no C equivalent
error: `extern` fn uses type `[u8]`, which is not FFI-safe
--> $DIR/lint-ctypes-94223.rs:20:7
--> $DIR/lint-94223.rs:20:7
|
LL | A(extern "C" fn([u8])),
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -58,7 +58,7 @@ LL | A(extern "C" fn([u8])),
= note: slices have no C equivalent
error: `extern` fn uses type `[u8]`, which is not FFI-safe
--> $DIR/lint-ctypes-94223.rs:24:12
--> $DIR/lint-94223.rs:24:12
|
LL | type Foo = extern "C" fn([u8]);
| ^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -67,7 +67,7 @@ LL | type Foo = extern "C" fn([u8]);
= note: slices have no C equivalent
error: `extern` fn uses type `Option<&<T as FooTrait>::FooType>`, which is not FFI-safe
--> $DIR/lint-ctypes-94223.rs:31:20
--> $DIR/lint-94223.rs:31:20
|
LL | pub type Foo2<T> = extern "C" fn(Option<&<T as FooTrait>::FooType>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -76,7 +76,7 @@ LL | pub type Foo2<T> = extern "C" fn(Option<&<T as FooTrait>::FooType>);
= note: enum has no representation hint
error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
--> $DIR/lint-ctypes-94223.rs:41:17
--> $DIR/lint-94223.rs:41:17
|
LL | pub static BAD: extern "C" fn(FfiUnsafe) = f;
| ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -84,13 +84,13 @@ LL | pub static BAD: extern "C" fn(FfiUnsafe) = f;
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
note: the type is defined here
--> $DIR/lint-ctypes-94223.rs:34:1
--> $DIR/lint-94223.rs:34:1
|
LL | pub struct FfiUnsafe;
| ^^^^^^^^^^^^^^^^^^^^
error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
--> $DIR/lint-ctypes-94223.rs:44:30
--> $DIR/lint-94223.rs:44:30
|
LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUnsafe)> = Ok(f);
| ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -98,13 +98,13 @@ LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUns
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
note: the type is defined here
--> $DIR/lint-ctypes-94223.rs:34:1
--> $DIR/lint-94223.rs:34:1
|
LL | pub struct FfiUnsafe;
| ^^^^^^^^^^^^^^^^^^^^
error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
--> $DIR/lint-ctypes-94223.rs:44:56
--> $DIR/lint-94223.rs:44:56
|
LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUnsafe)> = Ok(f);
| ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -112,13 +112,13 @@ LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUns
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
note: the type is defined here
--> $DIR/lint-ctypes-94223.rs:34:1
--> $DIR/lint-94223.rs:34:1
|
LL | pub struct FfiUnsafe;
| ^^^^^^^^^^^^^^^^^^^^
error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe
--> $DIR/lint-ctypes-94223.rs:48:22
--> $DIR/lint-94223.rs:48:22
|
LL | pub const BAD_CONST: extern "C" fn(FfiUnsafe) = f;
| ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -126,7 +126,7 @@ LL | pub const BAD_CONST: extern "C" fn(FfiUnsafe) = f;
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
note: the type is defined here
--> $DIR/lint-ctypes-94223.rs:34:1
--> $DIR/lint-94223.rs:34:1
|
LL | pub struct FfiUnsafe;
| ^^^^^^^^^^^^^^^^^^^^

View file

@ -1,5 +1,5 @@
error: `extern` block uses type `CStr`, which is not FFI-safe
--> $DIR/lint-ctypes-cstr.rs:7:21
--> $DIR/lint-cstr.rs:7:21
|
LL | fn take_cstr(s: CStr);
| ^^^^ not FFI-safe
@ -7,13 +7,13 @@ LL | fn take_cstr(s: CStr);
= help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
= note: `CStr`/`CString` do not have a guaranteed layout
note: the lint level is defined here
--> $DIR/lint-ctypes-cstr.rs:2:9
--> $DIR/lint-cstr.rs:2:9
|
LL | #![deny(improper_ctypes, improper_ctypes_definitions)]
| ^^^^^^^^^^^^^^^
error: `extern` block uses type `CStr`, which is not FFI-safe
--> $DIR/lint-ctypes-cstr.rs:10:25
--> $DIR/lint-cstr.rs:10:25
|
LL | fn take_cstr_ref(s: &CStr);
| ^^^^^ not FFI-safe
@ -22,7 +22,7 @@ LL | fn take_cstr_ref(s: &CStr);
= note: `CStr`/`CString` do not have a guaranteed layout
error: `extern` block uses type `CString`, which is not FFI-safe
--> $DIR/lint-ctypes-cstr.rs:13:24
--> $DIR/lint-cstr.rs:13:24
|
LL | fn take_cstring(s: CString);
| ^^^^^^^ not FFI-safe
@ -31,7 +31,7 @@ LL | fn take_cstring(s: CString);
= note: `CStr`/`CString` do not have a guaranteed layout
error: `extern` block uses type `CString`, which is not FFI-safe
--> $DIR/lint-ctypes-cstr.rs:16:28
--> $DIR/lint-cstr.rs:16:28
|
LL | fn take_cstring_ref(s: &CString);
| ^^^^^^^^ not FFI-safe
@ -40,7 +40,7 @@ LL | fn take_cstring_ref(s: &CString);
= note: `CStr`/`CString` do not have a guaranteed layout
error: `extern` block uses type `CString`, which is not FFI-safe
--> $DIR/lint-ctypes-cstr.rs:20:43
--> $DIR/lint-cstr.rs:20:43
|
LL | fn no_special_help_for_mut_cstring(s: *mut CString);
| ^^^^^^^^^^^^ not FFI-safe
@ -49,7 +49,7 @@ LL | fn no_special_help_for_mut_cstring(s: *mut CString);
= note: this struct has unspecified layout
error: `extern` block uses type `CString`, which is not FFI-safe
--> $DIR/lint-ctypes-cstr.rs:24:47
--> $DIR/lint-cstr.rs:24:47
|
LL | fn no_special_help_for_mut_cstring_ref(s: &mut CString);
| ^^^^^^^^^^^^ not FFI-safe
@ -58,7 +58,7 @@ LL | fn no_special_help_for_mut_cstring_ref(s: &mut CString);
= note: this struct has unspecified layout
error: `extern` fn uses type `CStr`, which is not FFI-safe
--> $DIR/lint-ctypes-cstr.rs:29:37
--> $DIR/lint-cstr.rs:29:37
|
LL | extern "C" fn rust_take_cstr_ref(s: &CStr) {}
| ^^^^^ not FFI-safe
@ -66,13 +66,13 @@ LL | extern "C" fn rust_take_cstr_ref(s: &CStr) {}
= help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
= note: `CStr`/`CString` do not have a guaranteed layout
note: the lint level is defined here
--> $DIR/lint-ctypes-cstr.rs:2:26
--> $DIR/lint-cstr.rs:2:26
|
LL | #![deny(improper_ctypes, improper_ctypes_definitions)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `extern` fn uses type `CString`, which is not FFI-safe
--> $DIR/lint-ctypes-cstr.rs:32:36
--> $DIR/lint-cstr.rs:32:36
|
LL | extern "C" fn rust_take_cstring(s: CString) {}
| ^^^^^^^ not FFI-safe

View file

@ -52,7 +52,6 @@ extern "C" {
pub fn str_type(p: &str); //~ ERROR: uses type `str`
pub fn box_type(p: Box<u32>); //~ ERROR uses type `Box<u32>`
pub fn opt_box_type(p: Option<Box<u32>>);
//~^ ERROR uses type `Option<Box<u32>>`
pub fn char_type(p: char); //~ ERROR uses type `char`
pub fn trait_type(p: &dyn Bar); //~ ERROR uses type `dyn Bar`
pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)`

View file

@ -67,17 +67,8 @@ LL | pub fn box_type(p: Box<u32>);
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
error: `extern` block uses type `Option<Box<u32>>`, which is not FFI-safe
--> $DIR/lint-ctypes.rs:54:28
|
LL | pub fn opt_box_type(p: Option<Box<u32>>);
| ^^^^^^^^^^^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint
error: `extern` block uses type `char`, which is not FFI-safe
--> $DIR/lint-ctypes.rs:56:25
--> $DIR/lint-ctypes.rs:55:25
|
LL | pub fn char_type(p: char);
| ^^^^ not FFI-safe
@ -86,7 +77,7 @@ LL | pub fn char_type(p: char);
= note: the `char` type has no C equivalent
error: `extern` block uses type `dyn Bar`, which is not FFI-safe
--> $DIR/lint-ctypes.rs:57:26
--> $DIR/lint-ctypes.rs:56:26
|
LL | pub fn trait_type(p: &dyn Bar);
| ^^^^^^^^ not FFI-safe
@ -94,7 +85,7 @@ LL | pub fn trait_type(p: &dyn Bar);
= note: trait objects have no C equivalent
error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
--> $DIR/lint-ctypes.rs:58:26
--> $DIR/lint-ctypes.rs:57:26
|
LL | pub fn tuple_type(p: (i32, i32));
| ^^^^^^^^^^ not FFI-safe
@ -103,7 +94,7 @@ LL | pub fn tuple_type(p: (i32, i32));
= note: tuples have unspecified layout
error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
--> $DIR/lint-ctypes.rs:59:27
--> $DIR/lint-ctypes.rs:58:27
|
LL | pub fn tuple_type2(p: I32Pair);
| ^^^^^^^ not FFI-safe
@ -112,7 +103,7 @@ LL | pub fn tuple_type2(p: I32Pair);
= note: tuples have unspecified layout
error: `extern` block uses type `ZeroSize`, which is not FFI-safe
--> $DIR/lint-ctypes.rs:60:25
--> $DIR/lint-ctypes.rs:59:25
|
LL | pub fn zero_size(p: ZeroSize);
| ^^^^^^^^ not FFI-safe
@ -126,7 +117,7 @@ LL | pub struct ZeroSize;
| ^^^^^^^^^^^^^^^^^^^
error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
--> $DIR/lint-ctypes.rs:61:33
--> $DIR/lint-ctypes.rs:60:33
|
LL | pub fn zero_size_phantom(p: ZeroSizeWithPhantomData);
| ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -139,7 +130,7 @@ LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `extern` block uses type `PhantomData<bool>`, which is not FFI-safe
--> $DIR/lint-ctypes.rs:64:12
--> $DIR/lint-ctypes.rs:63:12
|
LL | -> ::std::marker::PhantomData<bool>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -147,7 +138,7 @@ LL | -> ::std::marker::PhantomData<bool>;
= note: composed only of `PhantomData`
error: `extern` block uses type `fn()`, which is not FFI-safe
--> $DIR/lint-ctypes.rs:65:23
--> $DIR/lint-ctypes.rs:64:23
|
LL | pub fn fn_type(p: RustFn);
| ^^^^^^ not FFI-safe
@ -156,7 +147,7 @@ LL | pub fn fn_type(p: RustFn);
= note: this function pointer has Rust-specific calling convention
error: `extern` block uses type `fn()`, which is not FFI-safe
--> $DIR/lint-ctypes.rs:66:24
--> $DIR/lint-ctypes.rs:65:24
|
LL | pub fn fn_type2(p: fn());
| ^^^^ not FFI-safe
@ -165,7 +156,7 @@ LL | pub fn fn_type2(p: fn());
= note: this function pointer has Rust-specific calling convention
error: `extern` block uses type `Box<u32>`, which is not FFI-safe
--> $DIR/lint-ctypes.rs:67:28
--> $DIR/lint-ctypes.rs:66:28
|
LL | pub fn fn_contained(p: RustBadRet);
| ^^^^^^^^^^ not FFI-safe
@ -174,7 +165,7 @@ LL | pub fn fn_contained(p: RustBadRet);
= note: this struct has unspecified layout
error: `extern` block uses type `str`, which is not FFI-safe
--> $DIR/lint-ctypes.rs:68:31
--> $DIR/lint-ctypes.rs:67:31
|
LL | pub fn transparent_str(p: TransparentStr);
| ^^^^^^^^^^^^^^ not FFI-safe
@ -183,7 +174,7 @@ LL | pub fn transparent_str(p: TransparentStr);
= note: string slices have no C equivalent
error: `extern` block uses type `Box<u32>`, which is not FFI-safe
--> $DIR/lint-ctypes.rs:69:30
--> $DIR/lint-ctypes.rs:68:30
|
LL | pub fn transparent_fn(p: TransparentBadFn);
| ^^^^^^^^^^^^^^^^ not FFI-safe
@ -192,7 +183,7 @@ LL | pub fn transparent_fn(p: TransparentBadFn);
= note: this struct has unspecified layout
error: `extern` block uses type `[u8; 8]`, which is not FFI-safe
--> $DIR/lint-ctypes.rs:70:27
--> $DIR/lint-ctypes.rs:69:27
|
LL | pub fn raw_array(arr: [u8; 8]);
| ^^^^^^^ not FFI-safe
@ -201,7 +192,7 @@ LL | pub fn raw_array(arr: [u8; 8]);
= note: passing raw arrays by value is not FFI-safe
error: `extern` block uses type `Option<UnsafeCell<extern "C" fn()>>`, which is not FFI-safe
--> $DIR/lint-ctypes.rs:72:26
--> $DIR/lint-ctypes.rs:71:26
|
LL | pub fn no_niche_a(a: Option<UnsafeCell<extern "C" fn()>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -210,7 +201,7 @@ LL | pub fn no_niche_a(a: Option<UnsafeCell<extern "C" fn()>>);
= note: enum has no representation hint
error: `extern` block uses type `Option<UnsafeCell<&i32>>`, which is not FFI-safe
--> $DIR/lint-ctypes.rs:74:26
--> $DIR/lint-ctypes.rs:73:26
|
LL | pub fn no_niche_b(b: Option<UnsafeCell<&i32>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -218,5 +209,5 @@ LL | pub fn no_niche_b(b: Option<UnsafeCell<&i32>>);
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint
error: aborting due to 22 previous errors
error: aborting due to 21 previous errors

View file

@ -1,5 +1,5 @@
error: `extern` block uses type `U`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:82:14
--> $DIR/lint-enum.rs:82:14
|
LL | fn uf(x: U);
| ^ not FFI-safe
@ -7,18 +7,18 @@ LL | fn uf(x: U);
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint
note: the type is defined here
--> $DIR/lint-ctypes-enum.rs:9:1
--> $DIR/lint-enum.rs:9:1
|
LL | enum U {
| ^^^^^^
note: the lint level is defined here
--> $DIR/lint-ctypes-enum.rs:2:9
--> $DIR/lint-enum.rs:2:9
|
LL | #![deny(improper_ctypes)]
| ^^^^^^^^^^^^^^^
error: `extern` block uses type `B`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:83:14
--> $DIR/lint-enum.rs:83:14
|
LL | fn bf(x: B);
| ^ not FFI-safe
@ -26,13 +26,13 @@ LL | fn bf(x: B);
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint
note: the type is defined here
--> $DIR/lint-ctypes-enum.rs:12:1
--> $DIR/lint-enum.rs:12:1
|
LL | enum B {
| ^^^^^^
error: `extern` block uses type `T`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:84:14
--> $DIR/lint-enum.rs:84:14
|
LL | fn tf(x: T);
| ^ not FFI-safe
@ -40,13 +40,13 @@ LL | fn tf(x: T);
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint
note: the type is defined here
--> $DIR/lint-ctypes-enum.rs:16:1
--> $DIR/lint-enum.rs:16:1
|
LL | enum T {
| ^^^^^^
error: `extern` block uses type `Option<TransparentUnion<NonZero<u8>>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:108:36
--> $DIR/lint-enum.rs:108:36
|
LL | fn option_transparent_union(x: Option<TransparentUnion<num::NonZero<u8>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -55,7 +55,7 @@ LL | fn option_transparent_union(x: Option<TransparentUnion<num::NonZero<u8>
= note: enum has no representation hint
error: `extern` block uses type `Option<Rust<NonZero<u8>>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:110:28
--> $DIR/lint-enum.rs:110:28
|
LL | fn option_repr_rust(x: Option<Rust<num::NonZero<u8>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -64,7 +64,7 @@ LL | fn option_repr_rust(x: Option<Rust<num::NonZero<u8>>>);
= note: enum has no representation hint
error: `extern` block uses type `Option<u8>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:111:21
--> $DIR/lint-enum.rs:111:21
|
LL | fn option_u8(x: Option<u8>);
| ^^^^^^^^^^ not FFI-safe
@ -73,7 +73,7 @@ LL | fn option_u8(x: Option<u8>);
= note: enum has no representation hint
error: `extern` block uses type `Result<TransparentUnion<NonZero<u8>>, ()>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:131:38
--> $DIR/lint-enum.rs:131:38
|
LL | fn result_transparent_union_t(x: Result<TransparentUnion<num::NonZero<u8>>, ()>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -82,7 +82,7 @@ LL | fn result_transparent_union_t(x: Result<TransparentUnion<num::NonZero<u
= note: enum has no representation hint
error: `extern` block uses type `Result<Rust<NonZero<u8>>, ()>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:133:30
--> $DIR/lint-enum.rs:133:30
|
LL | fn result_repr_rust_t(x: Result<Rust<num::NonZero<u8>>, ()>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -91,7 +91,7 @@ LL | fn result_repr_rust_t(x: Result<Rust<num::NonZero<u8>>, ()>);
= note: enum has no representation hint
error: `extern` block uses type `Result<NonZero<u8>, U>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:137:51
--> $DIR/lint-enum.rs:137:51
|
LL | fn result_1zst_exhaustive_single_variant_t(x: Result<num::NonZero<u8>, U>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -100,7 +100,7 @@ LL | fn result_1zst_exhaustive_single_variant_t(x: Result<num::NonZero<u8>,
= note: enum has no representation hint
error: `extern` block uses type `Result<NonZero<u8>, B>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:139:53
--> $DIR/lint-enum.rs:139:53
|
LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>, B>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -109,7 +109,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>
= note: enum has no representation hint
error: `extern` block uses type `Result<NonZero<u8>, NonExhaustive>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:141:51
--> $DIR/lint-enum.rs:141:51
|
LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, NonExhaustive>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -118,7 +118,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>,
= note: enum has no representation hint
error: `extern` block uses type `Result<NonZero<u8>, Field>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:144:49
--> $DIR/lint-enum.rs:144:49
|
LL | fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Field>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -127,7 +127,7 @@ LL | fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Fi
= note: enum has no representation hint
error: `extern` block uses type `Result<Result<(), NonZero<u8>>, ()>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:146:30
--> $DIR/lint-enum.rs:146:30
|
LL | fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -136,7 +136,7 @@ LL | fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>);
= note: enum has no representation hint
error: `extern` block uses type `Result<(), TransparentUnion<NonZero<u8>>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:167:38
--> $DIR/lint-enum.rs:167:38
|
LL | fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZero<u8>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -145,7 +145,7 @@ LL | fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZe
= note: enum has no representation hint
error: `extern` block uses type `Result<(), Rust<NonZero<u8>>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:169:30
--> $DIR/lint-enum.rs:169:30
|
LL | fn result_repr_rust_e(x: Result<(), Rust<num::NonZero<u8>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -154,7 +154,7 @@ LL | fn result_repr_rust_e(x: Result<(), Rust<num::NonZero<u8>>>);
= note: enum has no representation hint
error: `extern` block uses type `Result<U, NonZero<u8>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:173:51
--> $DIR/lint-enum.rs:173:51
|
LL | fn result_1zst_exhaustive_single_variant_e(x: Result<U, num::NonZero<u8>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -163,7 +163,7 @@ LL | fn result_1zst_exhaustive_single_variant_e(x: Result<U, num::NonZero<u8
= note: enum has no representation hint
error: `extern` block uses type `Result<B, NonZero<u8>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:175:53
--> $DIR/lint-enum.rs:175:53
|
LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<u8>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -172,7 +172,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<
= note: enum has no representation hint
error: `extern` block uses type `Result<NonExhaustive, NonZero<u8>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:177:51
--> $DIR/lint-enum.rs:177:51
|
LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num::NonZero<u8>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -181,7 +181,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num
= note: enum has no representation hint
error: `extern` block uses type `Result<Field, NonZero<u8>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:180:49
--> $DIR/lint-enum.rs:180:49
|
LL | fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<u8>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -190,7 +190,7 @@ LL | fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<
= note: enum has no representation hint
error: `extern` block uses type `Result<(), Result<(), NonZero<u8>>>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:182:30
--> $DIR/lint-enum.rs:182:30
|
LL | fn result_cascading_e(x: Result<(), Result<(), num::NonZero<u8>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -199,7 +199,7 @@ LL | fn result_cascading_e(x: Result<(), Result<(), num::NonZero<u8>>>);
= note: enum has no representation hint
error: `extern` block uses type `Result<(), ()>`, which is not FFI-safe
--> $DIR/lint-ctypes-enum.rs:184:27
--> $DIR/lint-enum.rs:184:27
|
LL | fn result_unit_t_e(x: Result<(), ()>);
| ^^^^^^^^^^^^^^ not FFI-safe

View file

@ -1,5 +1,5 @@
error: `extern` fn uses type `[u32]`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:70:33
--> $DIR/lint-fn.rs:70:33
|
LL | pub extern "C" fn slice_type(p: &[u32]) { }
| ^^^^^^ not FFI-safe
@ -7,13 +7,13 @@ LL | pub extern "C" fn slice_type(p: &[u32]) { }
= help: consider using a raw pointer instead
= note: slices have no C equivalent
note: the lint level is defined here
--> $DIR/lint-ctypes-fn.rs:2:9
--> $DIR/lint-fn.rs:2:9
|
LL | #![deny(improper_ctypes_definitions)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `extern` fn uses type `str`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:73:31
--> $DIR/lint-fn.rs:73:31
|
LL | pub extern "C" fn str_type(p: &str) { }
| ^^^^ not FFI-safe
@ -22,7 +22,7 @@ LL | pub extern "C" fn str_type(p: &str) { }
= note: string slices have no C equivalent
error: `extern` fn uses type `Box<[u8]>`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:80:34
--> $DIR/lint-fn.rs:80:34
|
LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { }
| ^^^^^^^^^ not FFI-safe
@ -30,7 +30,7 @@ LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { }
= note: box cannot be represented as a single pointer
error: `extern` fn uses type `Box<str>`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:83:35
--> $DIR/lint-fn.rs:83:35
|
LL | pub extern "C" fn boxed_string(p: Box<str>) { }
| ^^^^^^^^ not FFI-safe
@ -38,7 +38,7 @@ LL | pub extern "C" fn boxed_string(p: Box<str>) { }
= note: box cannot be represented as a single pointer
error: `extern` fn uses type `Box<dyn Trait>`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:86:34
--> $DIR/lint-fn.rs:86:34
|
LL | pub extern "C" fn boxed_trait(p: Box<dyn Trait>) { }
| ^^^^^^^^^^^^^^ not FFI-safe
@ -46,7 +46,7 @@ LL | pub extern "C" fn boxed_trait(p: Box<dyn Trait>) { }
= note: box cannot be represented as a single pointer
error: `extern` fn uses type `char`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:89:32
--> $DIR/lint-fn.rs:89:32
|
LL | pub extern "C" fn char_type(p: char) { }
| ^^^^ not FFI-safe
@ -55,7 +55,7 @@ LL | pub extern "C" fn char_type(p: char) { }
= note: the `char` type has no C equivalent
error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:92:33
--> $DIR/lint-fn.rs:92:33
|
LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
| ^^^^^^^^^^ not FFI-safe
@ -64,7 +64,7 @@ LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
= note: tuples have unspecified layout
error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:95:34
--> $DIR/lint-fn.rs:95:34
|
LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
| ^^^^^^^ not FFI-safe
@ -73,7 +73,7 @@ LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
= note: tuples have unspecified layout
error: `extern` fn uses type `ZeroSize`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:98:32
--> $DIR/lint-fn.rs:98:32
|
LL | pub extern "C" fn zero_size(p: ZeroSize) { }
| ^^^^^^^^ not FFI-safe
@ -81,26 +81,26 @@ LL | pub extern "C" fn zero_size(p: ZeroSize) { }
= help: consider adding a member to this struct
= note: this struct has no fields
note: the type is defined here
--> $DIR/lint-ctypes-fn.rs:25:1
--> $DIR/lint-fn.rs:25:1
|
LL | pub struct ZeroSize;
| ^^^^^^^^^^^^^^^^^^^
error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:101:40
--> $DIR/lint-fn.rs:101:40
|
LL | pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
| ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: composed only of `PhantomData`
note: the type is defined here
--> $DIR/lint-ctypes-fn.rs:60:1
--> $DIR/lint-fn.rs:60:1
|
LL | pub struct ZeroSizeWithPhantomData(PhantomData<i32>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `extern` fn uses type `PhantomData<bool>`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:104:51
--> $DIR/lint-fn.rs:104:51
|
LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
| ^^^^^^^^^^^^^^^^^ not FFI-safe
@ -108,7 +108,7 @@ LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
= note: composed only of `PhantomData`
error: `extern` fn uses type `fn()`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:109:30
--> $DIR/lint-fn.rs:109:30
|
LL | pub extern "C" fn fn_type(p: RustFn) { }
| ^^^^^^ not FFI-safe
@ -117,7 +117,7 @@ LL | pub extern "C" fn fn_type(p: RustFn) { }
= note: this function pointer has Rust-specific calling convention
error: `extern` fn uses type `fn()`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:112:31
--> $DIR/lint-fn.rs:112:31
|
LL | pub extern "C" fn fn_type2(p: fn()) { }
| ^^^^ not FFI-safe
@ -126,7 +126,7 @@ LL | pub extern "C" fn fn_type2(p: fn()) { }
= note: this function pointer has Rust-specific calling convention
error: `extern` fn uses type `str`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:117:38
--> $DIR/lint-fn.rs:117:38
|
LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
| ^^^^^^^^^^^^^^ not FFI-safe
@ -135,7 +135,7 @@ LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
= note: string slices have no C equivalent
error: `extern` fn uses type `PhantomData<bool>`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:169:43
--> $DIR/lint-fn.rs:169:43
|
LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
| ^^^^^^^^^^^^^^^^^ not FFI-safe
@ -143,7 +143,7 @@ LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
= note: composed only of `PhantomData`
error: `extern` fn uses type `Vec<T>`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:182:39
--> $DIR/lint-fn.rs:182:39
|
LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
| ^^^^^^ not FFI-safe
@ -152,7 +152,7 @@ LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
= note: this struct has unspecified layout
error: `extern` fn uses type `Vec<T>`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:185:41
--> $DIR/lint-fn.rs:185:41
|
LL | pub extern "C" fn used_generic5<T>() -> Vec<T> {
| ^^^^^^ not FFI-safe

View file

@ -1,5 +1,5 @@
error: `extern` fn uses type `Option<&T>`, which is not FFI-safe
--> $DIR/lint-ctypes-option-nonnull-unsized.rs:3:45
--> $DIR/lint-option-nonnull-unsized.rs:3:45
|
LL | extern "C" fn foo<T: ?Sized + 'static>() -> Option<&'static T> {
| ^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -7,7 +7,7 @@ LL | extern "C" fn foo<T: ?Sized + 'static>() -> Option<&'static T> {
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint
note: the lint level is defined here
--> $DIR/lint-ctypes-option-nonnull-unsized.rs:1:9
--> $DIR/lint-option-nonnull-unsized.rs:1:9
|
LL | #![deny(improper_ctypes_definitions)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -1,5 +1,5 @@
warning: `extern` fn uses type `()`, which is not FFI-safe
--> $DIR/improper_ctypes_definitions_ice_134060.rs:11:34
--> $DIR/mustpass-134060.rs:11:34
|
LL | extern "C" fn foo_(&self, _: ()) -> i64 {
| ^^ not FFI-safe