diff options
| author | niacdoial <niac.notirl@gmail.com> | 2025-08-22 23:07:40 +0200 |
|---|---|---|
| committer | niacdoial <niac.notirl@gmail.com> | 2025-09-06 21:46:33 +0200 |
| commit | 0c0e764ff7d0708b90baa1386c6cbe75d70bce7d (patch) | |
| tree | c29cafbc7d0e62e81fa47993e4983a0fadd1bd8e | |
| parent | 0d0f4eac8b98133e5da6d3604d86a8f3b5a67844 (diff) | |
| download | rust-0c0e764ff7d0708b90baa1386c6cbe75d70bce7d.tar.gz rust-0c0e764ff7d0708b90baa1386c6cbe75d70bce7d.zip | |
ImproperCTypes: move code and tests into proper directories
| -rw-r--r-- | compiler/rustc_lint/src/types.rs | 867 | ||||
| -rw-r--r-- | compiler/rustc_lint/src/types/improper_ctypes.rs | 861 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/allow-phantomdata-in-ffi.rs (renamed from tests/ui/lint/improper_ctypes/allow-phantomdata-in-ffi.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-113436-1.rs (renamed from tests/ui/lint/lint-ctypes-113436-1.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-113436-1.stderr (renamed from tests/ui/lint/lint-ctypes-113436-1.stderr) | 10 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-73249-2.rs (renamed from tests/ui/lint/lint-ctypes-73249-2.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-73249-2.stderr (renamed from tests/ui/lint/lint-ctypes-73249-2.stderr) | 4 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-73249-3.rs (renamed from tests/ui/lint/lint-ctypes-73249-3.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-73249-3.stderr (renamed from tests/ui/lint/lint-ctypes-73249-5.stderr) | 4 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-73249-5.rs (renamed from tests/ui/lint/lint-ctypes-73249-5.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-73249-5.stderr (renamed from tests/ui/lint/lint-ctypes-73249-3.stderr) | 4 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-73251-1.rs (renamed from tests/ui/lint/lint-ctypes-73251-1.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-73251-1.stderr (renamed from tests/ui/lint/lint-ctypes-73251-1.stderr) | 4 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-73251-2.rs (renamed from tests/ui/lint/lint-ctypes-73251-2.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-73251-2.stderr (renamed from tests/ui/lint/lint-ctypes-73251-2.stderr) | 4 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-94223.rs (renamed from tests/ui/lint/lint-ctypes-94223.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-94223.stderr (renamed from tests/ui/lint/lint-ctypes-94223.stderr) | 34 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-cstr.rs (renamed from tests/ui/lint/lint-ctypes-cstr.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-cstr.stderr (renamed from tests/ui/lint/lint-ctypes-cstr.stderr) | 20 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-ctypes.rs (renamed from tests/ui/lint/lint-ctypes.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-ctypes.stderr (renamed from tests/ui/lint/lint-ctypes.stderr) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-enum.rs (renamed from tests/ui/lint/lint-ctypes-enum.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-enum.stderr (renamed from tests/ui/lint/lint-ctypes-enum.stderr) | 50 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-fn.rs (renamed from tests/ui/lint/lint-ctypes-fn.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-fn.stderr (renamed from tests/ui/lint/lint-ctypes-fn.stderr) | 40 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-non-recursion-limit.rs (renamed from tests/ui/lint/lint-ctypes-non-recursion-limit.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-option-nonnull-unsized.rs (renamed from tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/lint-option-nonnull-unsized.stderr (renamed from tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr) | 4 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/mustpass-113436.rs (renamed from tests/ui/lint/lint-ctypes-113436.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/mustpass-113900.rs (renamed from tests/ui/lint/lint-ctypes-113900.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/mustpass-134060.rs (renamed from tests/ui/lint/improper_ctypes_definitions_ice_134060.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/mustpass-134060.stderr (renamed from tests/ui/lint/improper_ctypes_definitions_ice_134060.stderr) | 2 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/mustpass-66202.rs (renamed from tests/ui/lint/lint-ctypes-66202.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/mustpass-73249-1.rs (renamed from tests/ui/lint/lint-ctypes-73249-1.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/mustpass-73249-4.rs (renamed from tests/ui/lint/lint-ctypes-73249-4.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/mustpass-73249.rs (renamed from tests/ui/lint/lint-ctypes-73249.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/mustpass-73251.rs (renamed from tests/ui/lint/lint-ctypes-73251.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/mustpass-73747.rs (renamed from tests/ui/lint/lint-ctypes-73747.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/repr-rust-is-undefined.rs (renamed from tests/ui/lint/improper_ctypes/repr-rust-is-undefined.rs) | 0 | ||||
| -rw-r--r-- | tests/ui/lint/improper-ctypes/repr-rust-is-undefined.stderr (renamed from tests/ui/lint/improper_ctypes/repr-rust-is-undefined.stderr) | 0 |
40 files changed, 959 insertions, 949 deletions
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index f8a692313f0..056ecb70af8 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1,35 +1,30 @@ 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::{ + CItemKind, ImproperCTypesDeclarations, ImproperCTypesDefinitions, +}; 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 +685,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>, @@ -1076,710 +933,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 { diff --git a/compiler/rustc_lint/src/types/improper_ctypes.rs b/compiler/rustc_lint/src/types/improper_ctypes.rs index 13afa540afc..6f732fc2a50 100644 --- a/compiler/rustc_lint/src/types/improper_ctypes.rs +++ b/compiler/rustc_lint/src/types/improper_ctypes.rs @@ -1,10 +1,140 @@ +use std::iter; use std::ops::ControlFlow; +use rustc_abi::VariantIdx; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::DiagMessage; use rustc_hir::def::CtorKind; -use rustc_middle::ty; +use rustc_hir::intravisit::VisitorExt; +use rustc_hir::{self as hir, AmbigArg}; +use rustc_middle::bug; +use rustc_middle::ty::{ + self, Adt, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, +}; +use rustc_session::{declare_lint, declare_lint_pass}; +use rustc_span::def_id::LocalDefId; +use rustc_span::{Span, sym}; +use tracing::debug; + +use super::repr_nullable_ptr; +use crate::lints::{ImproperCTypes, UsesPowerAlignment}; +use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent}; + + +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]); -use crate::fluent_generated as fluent; /// Check a variant of a non-exhaustive enum for improper ctypes /// @@ -41,3 +171,730 @@ fn variant_has_complex_ctor(variant: &ty::VariantDef) -> bool { // CtorKind::Const means a "unit" ctor !matches!(variant.ctor_kind(), Some(CtorKind::Const)) } + +#[derive(Clone, Copy)] +pub(crate) enum CItemKind { + Declaration, + Definition, +} + +enum FfiResult<'tcx> { + FfiSafe, + FfiPhantom(Ty<'tcx>), + FfiUnsafe { ty: Ty<'tcx>, reason: DiagMessage, help: Option<DiagMessage> }, +} + +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>, +} + +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) = super::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), + }; + } + + 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); + } + } +} diff --git a/tests/ui/lint/improper_ctypes/allow-phantomdata-in-ffi.rs b/tests/ui/lint/improper-ctypes/allow-phantomdata-in-ffi.rs index a90159d2b58..a90159d2b58 100644 --- a/tests/ui/lint/improper_ctypes/allow-phantomdata-in-ffi.rs +++ b/tests/ui/lint/improper-ctypes/allow-phantomdata-in-ffi.rs diff --git a/tests/ui/lint/lint-ctypes-113436-1.rs b/tests/ui/lint/improper-ctypes/lint-113436-1.rs index 1ca59c6868d..1ca59c6868d 100644 --- a/tests/ui/lint/lint-ctypes-113436-1.rs +++ b/tests/ui/lint/improper-ctypes/lint-113436-1.rs diff --git a/tests/ui/lint/lint-ctypes-113436-1.stderr b/tests/ui/lint/improper-ctypes/lint-113436-1.stderr index 7b63043f057..f01dc3b6e0d 100644 --- a/tests/ui/lint/lint-ctypes-113436-1.stderr +++ b/tests/ui/lint/improper-ctypes/lint-113436-1.stderr @@ -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); | ^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/lint-ctypes-73249-2.rs b/tests/ui/lint/improper-ctypes/lint-73249-2.rs index 31af0e3d381..31af0e3d381 100644 --- a/tests/ui/lint/lint-ctypes-73249-2.rs +++ b/tests/ui/lint/improper-ctypes/lint-73249-2.rs diff --git a/tests/ui/lint/lint-ctypes-73249-2.stderr b/tests/ui/lint/improper-ctypes/lint-73249-2.stderr index 2d0dfe94f09..d6c1cec2bd6 100644 --- a/tests/ui/lint/lint-ctypes-73249-2.stderr +++ b/tests/ui/lint/improper-ctypes/lint-73249-2.stderr @@ -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)] | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/lint-ctypes-73249-3.rs b/tests/ui/lint/improper-ctypes/lint-73249-3.rs index 8bdf536bf77..8bdf536bf77 100644 --- a/tests/ui/lint/lint-ctypes-73249-3.rs +++ b/tests/ui/lint/improper-ctypes/lint-73249-3.rs diff --git a/tests/ui/lint/lint-ctypes-73249-5.stderr b/tests/ui/lint/improper-ctypes/lint-73249-3.stderr index c4fa955de05..ebc9eb5eb82 100644 --- a/tests/ui/lint/lint-ctypes-73249-5.stderr +++ b/tests/ui/lint/improper-ctypes/lint-73249-3.stderr @@ -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)] | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/lint-ctypes-73249-5.rs b/tests/ui/lint/improper-ctypes/lint-73249-5.rs index cc6da59950d..cc6da59950d 100644 --- a/tests/ui/lint/lint-ctypes-73249-5.rs +++ b/tests/ui/lint/improper-ctypes/lint-73249-5.rs diff --git a/tests/ui/lint/lint-ctypes-73249-3.stderr b/tests/ui/lint/improper-ctypes/lint-73249-5.stderr index e1a313a2906..484927f57fe 100644 --- a/tests/ui/lint/lint-ctypes-73249-3.stderr +++ b/tests/ui/lint/improper-ctypes/lint-73249-5.stderr @@ -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)] | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/lint-ctypes-73251-1.rs b/tests/ui/lint/improper-ctypes/lint-73251-1.rs index 07ae05be69f..07ae05be69f 100644 --- a/tests/ui/lint/lint-ctypes-73251-1.rs +++ b/tests/ui/lint/improper-ctypes/lint-73251-1.rs diff --git a/tests/ui/lint/lint-ctypes-73251-1.stderr b/tests/ui/lint/improper-ctypes/lint-73251-1.stderr index 675a9de51cd..749722f0e22 100644 --- a/tests/ui/lint/lint-ctypes-73251-1.stderr +++ b/tests/ui/lint/improper-ctypes/lint-73251-1.stderr @@ -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)] | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/lint-ctypes-73251-2.rs b/tests/ui/lint/improper-ctypes/lint-73251-2.rs index c47118672e0..c47118672e0 100644 --- a/tests/ui/lint/lint-ctypes-73251-2.rs +++ b/tests/ui/lint/improper-ctypes/lint-73251-2.rs diff --git a/tests/ui/lint/lint-ctypes-73251-2.stderr b/tests/ui/lint/improper-ctypes/lint-73251-2.stderr index 634950b29ed..3770b7d789f 100644 --- a/tests/ui/lint/lint-ctypes-73251-2.stderr +++ b/tests/ui/lint/improper-ctypes/lint-73251-2.stderr @@ -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)] | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/lint-ctypes-94223.rs b/tests/ui/lint/improper-ctypes/lint-94223.rs index ac24f61b0ac..ac24f61b0ac 100644 --- a/tests/ui/lint/lint-ctypes-94223.rs +++ b/tests/ui/lint/improper-ctypes/lint-94223.rs diff --git a/tests/ui/lint/lint-ctypes-94223.stderr b/tests/ui/lint/improper-ctypes/lint-94223.stderr index bd127cf6004..008debf8f01 100644 --- a/tests/ui/lint/lint-ctypes-94223.stderr +++ b/tests/ui/lint/improper-ctypes/lint-94223.stderr @@ -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; | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/lint-ctypes-cstr.rs b/tests/ui/lint/improper-ctypes/lint-cstr.rs index b04decd0bca..b04decd0bca 100644 --- a/tests/ui/lint/lint-ctypes-cstr.rs +++ b/tests/ui/lint/improper-ctypes/lint-cstr.rs diff --git a/tests/ui/lint/lint-ctypes-cstr.stderr b/tests/ui/lint/improper-ctypes/lint-cstr.stderr index 8957758d577..da263065843 100644 --- a/tests/ui/lint/lint-ctypes-cstr.stderr +++ b/tests/ui/lint/improper-ctypes/lint-cstr.stderr @@ -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 diff --git a/tests/ui/lint/lint-ctypes.rs b/tests/ui/lint/improper-ctypes/lint-ctypes.rs index 47586c826ab..47586c826ab 100644 --- a/tests/ui/lint/lint-ctypes.rs +++ b/tests/ui/lint/improper-ctypes/lint-ctypes.rs diff --git a/tests/ui/lint/lint-ctypes.stderr b/tests/ui/lint/improper-ctypes/lint-ctypes.stderr index 3fb36647d4f..3fb36647d4f 100644 --- a/tests/ui/lint/lint-ctypes.stderr +++ b/tests/ui/lint/improper-ctypes/lint-ctypes.stderr diff --git a/tests/ui/lint/lint-ctypes-enum.rs b/tests/ui/lint/improper-ctypes/lint-enum.rs index f900f998d06..f900f998d06 100644 --- a/tests/ui/lint/lint-ctypes-enum.rs +++ b/tests/ui/lint/improper-ctypes/lint-enum.rs diff --git a/tests/ui/lint/lint-ctypes-enum.stderr b/tests/ui/lint/improper-ctypes/lint-enum.stderr index 40d22723309..35d1dcb87fd 100644 --- a/tests/ui/lint/lint-ctypes-enum.stderr +++ b/tests/ui/lint/improper-ctypes/lint-enum.stderr @@ -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 diff --git a/tests/ui/lint/lint-ctypes-fn.rs b/tests/ui/lint/improper-ctypes/lint-fn.rs index 0b84098e390..0b84098e390 100644 --- a/tests/ui/lint/lint-ctypes-fn.rs +++ b/tests/ui/lint/improper-ctypes/lint-fn.rs diff --git a/tests/ui/lint/lint-ctypes-fn.stderr b/tests/ui/lint/improper-ctypes/lint-fn.stderr index a19c04a63b5..34e3bd021b9 100644 --- a/tests/ui/lint/lint-ctypes-fn.stderr +++ b/tests/ui/lint/improper-ctypes/lint-fn.stderr @@ -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 diff --git a/tests/ui/lint/lint-ctypes-non-recursion-limit.rs b/tests/ui/lint/improper-ctypes/lint-non-recursion-limit.rs index 61e95dc5a46..61e95dc5a46 100644 --- a/tests/ui/lint/lint-ctypes-non-recursion-limit.rs +++ b/tests/ui/lint/improper-ctypes/lint-non-recursion-limit.rs diff --git a/tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs b/tests/ui/lint/improper-ctypes/lint-option-nonnull-unsized.rs index ca08eb23a57..ca08eb23a57 100644 --- a/tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs +++ b/tests/ui/lint/improper-ctypes/lint-option-nonnull-unsized.rs diff --git a/tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr b/tests/ui/lint/improper-ctypes/lint-option-nonnull-unsized.stderr index 74630469416..b17fb6bd614 100644 --- a/tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr +++ b/tests/ui/lint/improper-ctypes/lint-option-nonnull-unsized.stderr @@ -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)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/lint-ctypes-113436.rs b/tests/ui/lint/improper-ctypes/mustpass-113436.rs index d5acdc45f92..d5acdc45f92 100644 --- a/tests/ui/lint/lint-ctypes-113436.rs +++ b/tests/ui/lint/improper-ctypes/mustpass-113436.rs diff --git a/tests/ui/lint/lint-ctypes-113900.rs b/tests/ui/lint/improper-ctypes/mustpass-113900.rs index 3dd196a4094..3dd196a4094 100644 --- a/tests/ui/lint/lint-ctypes-113900.rs +++ b/tests/ui/lint/improper-ctypes/mustpass-113900.rs diff --git a/tests/ui/lint/improper_ctypes_definitions_ice_134060.rs b/tests/ui/lint/improper-ctypes/mustpass-134060.rs index b30be996736..b30be996736 100644 --- a/tests/ui/lint/improper_ctypes_definitions_ice_134060.rs +++ b/tests/ui/lint/improper-ctypes/mustpass-134060.rs diff --git a/tests/ui/lint/improper_ctypes_definitions_ice_134060.stderr b/tests/ui/lint/improper-ctypes/mustpass-134060.stderr index f6ac9a92cd5..791b2f73709 100644 --- a/tests/ui/lint/improper_ctypes_definitions_ice_134060.stderr +++ b/tests/ui/lint/improper-ctypes/mustpass-134060.stderr @@ -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 diff --git a/tests/ui/lint/lint-ctypes-66202.rs b/tests/ui/lint/improper-ctypes/mustpass-66202.rs index e4cfa54c8d8..e4cfa54c8d8 100644 --- a/tests/ui/lint/lint-ctypes-66202.rs +++ b/tests/ui/lint/improper-ctypes/mustpass-66202.rs diff --git a/tests/ui/lint/lint-ctypes-73249-1.rs b/tests/ui/lint/improper-ctypes/mustpass-73249-1.rs index 0ca91ef294f..0ca91ef294f 100644 --- a/tests/ui/lint/lint-ctypes-73249-1.rs +++ b/tests/ui/lint/improper-ctypes/mustpass-73249-1.rs diff --git a/tests/ui/lint/lint-ctypes-73249-4.rs b/tests/ui/lint/improper-ctypes/mustpass-73249-4.rs index 37099c1313a..37099c1313a 100644 --- a/tests/ui/lint/lint-ctypes-73249-4.rs +++ b/tests/ui/lint/improper-ctypes/mustpass-73249-4.rs diff --git a/tests/ui/lint/lint-ctypes-73249.rs b/tests/ui/lint/improper-ctypes/mustpass-73249.rs index c5f2318ef0a..c5f2318ef0a 100644 --- a/tests/ui/lint/lint-ctypes-73249.rs +++ b/tests/ui/lint/improper-ctypes/mustpass-73249.rs diff --git a/tests/ui/lint/lint-ctypes-73251.rs b/tests/ui/lint/improper-ctypes/mustpass-73251.rs index 15c1dfcaabf..15c1dfcaabf 100644 --- a/tests/ui/lint/lint-ctypes-73251.rs +++ b/tests/ui/lint/improper-ctypes/mustpass-73251.rs diff --git a/tests/ui/lint/lint-ctypes-73747.rs b/tests/ui/lint/improper-ctypes/mustpass-73747.rs index a2562e3b421..a2562e3b421 100644 --- a/tests/ui/lint/lint-ctypes-73747.rs +++ b/tests/ui/lint/improper-ctypes/mustpass-73747.rs diff --git a/tests/ui/lint/improper_ctypes/repr-rust-is-undefined.rs b/tests/ui/lint/improper-ctypes/repr-rust-is-undefined.rs index 379c4132404..379c4132404 100644 --- a/tests/ui/lint/improper_ctypes/repr-rust-is-undefined.rs +++ b/tests/ui/lint/improper-ctypes/repr-rust-is-undefined.rs diff --git a/tests/ui/lint/improper_ctypes/repr-rust-is-undefined.stderr b/tests/ui/lint/improper-ctypes/repr-rust-is-undefined.stderr index 5f0465bcf00..5f0465bcf00 100644 --- a/tests/ui/lint/improper_ctypes/repr-rust-is-undefined.stderr +++ b/tests/ui/lint/improper-ctypes/repr-rust-is-undefined.stderr |
