diff --git a/compiler/rustc_lint/src/c_void.rs b/compiler/rustc_lint/src/c_void.rs new file mode 100644 index 0000000000000..8d9ca2b1e40c8 --- /dev/null +++ b/compiler/rustc_lint/src/c_void.rs @@ -0,0 +1,227 @@ +use rustc_abi::ExternAbi; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{self as hir, LangItem}; +use rustc_middle::ty; +use rustc_session::lint::builtin::C_VOID_REFERENCES; +use rustc_session::{declare_lint, declare_lint_pass}; +use rustc_span::Span; + +use crate::lints::{ + CVoidConst, CVoidParameter, CVoidReference, CVoidReturn, CVoidStatic, ExternCVoidReturn, +}; +use crate::{LateContext, LateLintPass, LintContext}; + +fn is_c_void(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { + if let hir::TyKind::Path(qpath) = ty.kind + && let Res::Def(.., def_id) = cx.qpath_res(&qpath, ty.hir_id) + { + // need to look through type aliases (like `std::os::raw::c_void`) + let def_id = if DefKind::TyAlias == cx.tcx.def_kind(def_id) + && let ty::Adt(adt_def, _) = cx.tcx.type_of(def_id).skip_binder().kind() + { + adt_def.did() + } else { + def_id + }; + cx.tcx.is_lang_item(def_id, LangItem::CVoid) + } else { + false + } +} + +declare_lint! { + /// The `c_void_parameters` lint detects the use of [`core::ffi::c_void`] as a parameter type. + /// + /// ### Example + /// + /// ```rust + /// use std::ffi::c_void; + /// + /// unsafe extern "C" { + /// fn foo(_: c_void); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// `c_void` is designed for use through a [`pointer`], equivalent to C's `void*` type. It is a + /// mistake to use it directly as a parameter type. If you intended to use a pointer type, use + /// `*mut c_void` or `*const c_void`. + /// + /// [`core::ffi::c_void`]: https://doc.rust-lang.org/core/ffi/enum.c_void.html + /// [`pointer`]: https://doc.rust-lang.org/core/primitive.pointer.html + /// [`()`]: https://doc.rust-lang.org/core/primitive.unit.html + pub C_VOID_PARAMETERS, + Warn, + "detects use of `c_void` as a parameter type" +} + +declare_lint! { + /// The `c_void_returns` lint detects the use of [`core::ffi::c_void`] as a return type. + /// + /// ### Example + /// + /// ```rust + /// use std::ffi::c_void; + /// + /// unsafe extern "C" { + /// fn foo() -> c_void; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// `c_void` is designed for use through a [`pointer`], equivalent to C's `void*` type. It is a + /// mistake to use it directly as a return type, and calling `extern` functions declared as such + /// may result in undefined behavior. C functions that return `void` must be declared to return + /// [`()`] in Rust (omitting the return type implicitly returns `()`). + /// + /// [`core::ffi::c_void`]: https://doc.rust-lang.org/core/ffi/enum.c_void.html + /// [`pointer`]: https://doc.rust-lang.org/core/primitive.pointer.html + /// [`()`]: https://doc.rust-lang.org/core/primitive.unit.html + pub C_VOID_RETURNS, + Warn, + "detects use of `c_void` as a return type" +} + +declare_lint_pass!(CVoidParamsAndReturns => [C_VOID_PARAMETERS, C_VOID_RETURNS]); + +impl<'tcx> LateLintPass<'tcx> for CVoidParamsAndReturns { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + fn_kind: FnKind<'tcx>, + decl: &'tcx hir::FnDecl<'tcx>, + _: &'tcx hir::Body<'tcx>, + _: Span, + _: LocalDefId, + ) { + check_fn_decl_for_c_void( + cx, + decl, + !matches!(fn_kind, FnKind::ItemFn(.., hir::FnHeader { abi: ExternAbi::Rust, .. })), + ); + } + + fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ForeignItem<'tcx>) { + if let hir::ForeignItemKind::Fn(sig, ..) = item.kind { + check_fn_decl_for_c_void(cx, sig.decl, true); + } + } + + fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'tcx>) { + if let hir::TraitItemKind::Fn(sig, ..) = item.kind { + check_fn_decl_for_c_void(cx, sig.decl, false); + } + } + + fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx, hir::AmbigArg>) { + if let hir::TyKind::FnPtr(fn_ptr_ty) = ty.kind { + check_fn_decl_for_c_void(cx, fn_ptr_ty.decl, fn_ptr_ty.abi != ExternAbi::Rust); + } + } +} + +fn check_fn_decl_for_c_void(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, is_extern: bool) { + if let hir::FnRetTy::Return(output_ty) = decl.output + && is_c_void(cx, output_ty) + { + let suggestion = + cx.sess().source_map().span_extend_to_prev_char(decl.output.span(), ')', true); + + if is_extern { + cx.emit_span_lint(C_VOID_RETURNS, decl.output.span(), ExternCVoidReturn { suggestion }); + } else { + cx.emit_span_lint(C_VOID_RETURNS, decl.output.span(), CVoidReturn { suggestion }); + } + } + + for param_ty in decl.inputs { + if is_c_void(cx, param_ty) { + cx.emit_span_lint(C_VOID_PARAMETERS, param_ty.span, CVoidParameter); + } + } +} + +declare_lint_pass!(CVoidReferences => [C_VOID_REFERENCES]); + +impl<'tcx> LateLintPass<'tcx> for CVoidReferences { + fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx, hir::AmbigArg>) { + if let hir::TyKind::Ref(_, hir::MutTy { ty: pointee_ty, .. }) = ty.kind + && is_c_void(cx, pointee_ty) + { + cx.emit_span_lint(C_VOID_REFERENCES, ty.span, CVoidReference); + } + } +} + +declare_lint! { + /// The `c_void_statics` lint detects the use of [`core::ffi::c_void`] as the type of a `static` or `const` item. + /// + /// ### Example + /// + /// ```rust + /// use std::ffi::c_void; + /// + /// unsafe extern "C" { + /// static FOO: c_void; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// `c_void` is designed for use through a [`raw pointer`], equivalent to C's `void*` type. + /// For historical reasons, Rust considers it to have size 1. For a `static` item used + /// only for its address, the correct type is [`()`]. + /// + /// [`core::ffi::c_void`]: https://doc.rust-lang.org/core/ffi/enum.c_void.html + /// [`raw pointer`]: https://doc.rust-lang.org/core/primitive.pointer.html + /// [`()`]: https://doc.rust-lang.org/core/primitive.unit.html + pub C_VOID_STATICS, + Warn, + "detects use of `c_void` as the type of a `static` or `const` item" +} + +declare_lint_pass!(CVoidStatics => [C_VOID_STATICS]); + +impl<'tcx> LateLintPass<'tcx> for CVoidStatics { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx rustc_hir::Item<'tcx>) { + match item.kind { + hir::ItemKind::Static(_mut, _name, ty, _) if is_c_void(cx, ty) => { + cx.emit_span_lint(C_VOID_STATICS, item.span, CVoidStatic { suggestion: ty.span }) + } + hir::ItemKind::Const(_name, _generics, ty, _) if is_c_void(cx, ty) => { + cx.emit_span_lint(C_VOID_STATICS, item.span, CVoidConst) + } + _ => (), + } + } + + fn check_foreign_item( + &mut self, + cx: &LateContext<'tcx>, + item: &'tcx rustc_hir::ForeignItem<'tcx>, + ) { + if let hir::ForeignItemKind::Static(ty, ..) = item.kind + && is_c_void(cx, ty) + { + cx.emit_span_lint(C_VOID_STATICS, item.span, CVoidStatic { suggestion: ty.span }) + } + } + + fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx rustc_hir::TraitItem<'tcx>) { + if let hir::TraitItemKind::Const(ty, ..) = item.kind + && is_c_void(cx, ty) + { + cx.emit_span_lint(C_VOID_STATICS, item.span, CVoidConst) + } + } +} diff --git a/compiler/rustc_lint/src/c_void_returns.rs b/compiler/rustc_lint/src/c_void_returns.rs deleted file mode 100644 index f4dd260dd5ae4..0000000000000 --- a/compiler/rustc_lint/src/c_void_returns.rs +++ /dev/null @@ -1,89 +0,0 @@ -use rustc_abi::ExternAbi; -use rustc_hir::def::Res; -use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::FnKind; -use rustc_hir::{self as hir, LangItem}; -use rustc_session::{declare_lint, declare_lint_pass}; -use rustc_span::Span; - -use crate::lints::{CVoidReturn, ExternCVoidReturn}; -use crate::{LateContext, LateLintPass, LintContext}; - -declare_lint! { - /// The `c_void_returns` lint detects the use of [`core::ffi::c_void`] as a return type. - /// - /// ### Example - /// - /// ```rust - /// use std::ffi::c_void; - /// - /// unsafe extern "C" { - /// fn foo() -> c_void; - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// `c_void` is designed for use through a [`pointer`], equivalent to C's `void*` type. It is a - /// mistake to use it directly as a return type, and calling `extern` functions declared as such - /// may result in undefined behavior. C functions that return `void` must be declared to return - /// [`()`] in Rust (omitting the return type implicitly returns `()`). - /// - /// [`core::ffi::c_void`]: https://doc.rust-lang.org/core/ffi/enum.c_void.html - /// [`pointer`]: https://doc.rust-lang.org/core/primitive.pointer.html - /// [`()`]: https://doc.rust-lang.org/core/primitive.unit.html - pub C_VOID_RETURNS, - Warn, - "detects use of `c_void` as a return type" -} - -declare_lint_pass!(CVoidReturns => [C_VOID_RETURNS]); - -impl<'tcx> LateLintPass<'tcx> for CVoidReturns { - fn check_fn( - &mut self, - cx: &LateContext<'tcx>, - fn_kind: FnKind<'tcx>, - decl: &'tcx hir::FnDecl<'tcx>, - _: &'tcx hir::Body<'tcx>, - _: Span, - _: LocalDefId, - ) { - check_decl( - cx, - decl, - !matches!(fn_kind, FnKind::ItemFn(.., hir::FnHeader { abi: ExternAbi::Rust, .. })), - ); - } - - fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ForeignItem<'tcx>) { - if let hir::ForeignItemKind::Fn(sig, ..) = item.kind { - check_decl(cx, sig.decl, true); - } - } - - fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx, hir::AmbigArg>) { - if let hir::TyKind::FnPtr(fn_ptr_ty) = ty.kind { - check_decl(cx, fn_ptr_ty.decl, fn_ptr_ty.abi != ExternAbi::Rust); - } - } -} - -fn check_decl(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, is_extern: bool) { - if let hir::FnRetTy::Return(output_ty) = decl.output - && let hir::TyKind::Path(qpath) = output_ty.kind - && let Res::Def(.., def_id) = cx.qpath_res(&qpath, output_ty.hir_id) - && cx.tcx.is_lang_item(def_id, LangItem::CVoid) - { - let suggestion = - cx.sess().source_map().span_extend_to_prev_char(decl.output.span(), ')', true); - - if is_extern { - cx.emit_span_lint(C_VOID_RETURNS, decl.output.span(), ExternCVoidReturn { suggestion }); - } else { - cx.emit_span_lint(C_VOID_RETURNS, decl.output.span(), CVoidReturn { suggestion }); - } - } -} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 244db06a11d60..70488d4e26096 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -33,7 +33,7 @@ mod async_closures; mod async_fn_in_trait; mod autorefs; pub mod builtin; -mod c_void_returns; +mod c_void; mod context; mod dangling; mod default_could_be_derived; @@ -88,7 +88,7 @@ use async_closures::AsyncClosureUsage; use async_fn_in_trait::AsyncFnInTrait; use autorefs::*; use builtin::*; -use c_void_returns::*; +use c_void::*; use dangling::*; use default_could_be_derived::DefaultCouldBeDerived; use deref_into_dyn_supertrait::*; @@ -272,7 +272,9 @@ late_lint_methods!( LifetimeSyntax: LifetimeSyntax, InternalEqTraitMethodImpls: InternalEqTraitMethodImpls, ImplicitProvenanceCasts: ImplicitProvenanceCasts, - CVoidReturns: CVoidReturns, + CVoidParamsAndReturns: CVoidParamsAndReturns, + CVoidReferences: CVoidReferences, + CVoidStatics: CVoidStatics, ] ] ); diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index b084b412417c5..217ada34292ce 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -612,7 +612,14 @@ pub(crate) enum BuiltinSpecialModuleNameUsed { Main, } -// c_void_return.rs +// c_void.rs +#[derive(Diagnostic)] +#[diag("`c_void` should not be used directly as the type of a function parameter")] +#[help("did you mean `*mut c_void` or `*const c_void`?")] +#[note("`c_void` is only used through raw pointers, for compatibility with `void` pointers")] +pub(crate) struct CVoidParameter; + +// c_void.rs #[derive(Diagnostic)] #[diag("`c_void` should not be used as a return type")] #[help("returning `()` in Rust is equivalent to returning `void` in C")] @@ -625,11 +632,11 @@ pub(crate) struct CVoidReturn { pub suggestion: Span, } -// c_void_return.rs +// c_void.rs #[derive(Diagnostic)] #[diag("declarations returning `c_void` are not compatible with C functions returning `void`")] #[help("returning `()` in Rust is equivalent to returning `void` in C")] -#[note("`c_void` is only used through raw pointers for compatibility with `void` pointers")] +#[note("`c_void` is only used through raw pointers, for compatibility with `void` pointers")] pub(crate) struct ExternCVoidReturn { #[suggestion( "remove the return type to implicitly return `()`", @@ -639,6 +646,30 @@ pub(crate) struct ExternCVoidReturn { pub suggestion: Span, } +// c_void.rs +#[derive(Diagnostic)] +#[diag("`c_void` should not be used as the referent of an `&` or `&mut` reference")] +#[help("use a raw pointer, or a reference to `()`, instead")] +#[note( + "for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior" +)] +pub(crate) struct CVoidReference; + +// c_void.rs +#[derive(Diagnostic)] +#[diag("`static` items should not have type `c_void`")] +#[help("for a `static` used only for its address, use `()` instead")] +#[note("`c_void` is only used through raw pointers, for compatibility with C `void` pointers")] +pub(crate) struct CVoidStatic { + #[suggestion("use `()` instead", code = "()", applicability = "maybe-incorrect")] + pub suggestion: Span, +} + +#[derive(Diagnostic)] +#[diag("`const` items should not have type `c_void`")] +#[note("`c_void` is only used through raw pointers, for compatibility with C `void` pointers")] +pub(crate) struct CVoidConst; + // deref_into_dyn_supertrait.rs #[derive(Diagnostic)] #[diag("this `Deref` implementation is covered by an implicit supertrait coercion")] diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 82b4dd5e2babd..fd41888906b65 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -34,6 +34,7 @@ pub mod hardwired { CONFLICTING_REPR_HINTS, CONST_EVALUATABLE_UNCHECKED, CONST_ITEM_MUTATION, + C_VOID_VALUES, DEAD_CODE, DEAD_CODE_PUB_IN_BINARY, DEPENDENCY_ON_UNIT_NEVER_TYPE_FALLBACK, @@ -1477,6 +1478,64 @@ declare_lint! { "detects attempts to mutate a `const` item", } +declare_lint! { + /// The `c_void_references` lint detects the use of [`core::ffi::c_void`] as the referent of an `&` or `&mut` reference. + /// + /// ### Example + /// + /// ```rust + /// use std::ffi::c_void; + /// + /// fn foo(v: &c_void) { + /// // .... + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// `c_void` is designed for use through a [`raw pointer`], equivalent to C's `void*` type. + /// However, for historical reasons, Rust considers it to have size 1, and so using it via + /// a Rust reference can easily cause Undefined Behavior. + /// + /// [`core::ffi::c_void`]: https://doc.rust-lang.org/core/ffi/enum.c_void.html + /// [`raw pointer`]: https://doc.rust-lang.org/core/primitive.pointer.html + /// [`()`]: https://doc.rust-lang.org/core/primitive.unit.html + pub C_VOID_REFERENCES, + Warn, + "detects use of `c_void` as the referent of a Rust reference type" +} + +declare_lint! { + /// The `c_void_values` lint detects the use of values of type [`core::ffi::c_void`] + /// + /// ### Example + /// + /// ```rust + /// use std::ffi::c_void; + /// + /// fn foo(v: *const c_void) { + /// let val = unsafe { v.read() }; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// `c_void` is designed for use through a [`raw pointer`], equivalent to C's `void*` type. + /// However, for historical reasons, Rust considers it to have size 1, and so using it directly + /// via a value can easily cause Undefined Behavior. + /// + /// [`core::ffi::c_void`]: https://doc.rust-lang.org/core/ffi/enum.c_void.html + /// [`raw pointer`]: https://doc.rust-lang.org/core/primitive.pointer.html + /// [`()`]: https://doc.rust-lang.org/core/primitive.unit.html + pub C_VOID_VALUES, + Warn, + "detects use of `c_void` as the referent of a Rust reference type" +} + declare_lint! { /// The `patterns_in_fns_without_body` lint detects `mut` identifier /// patterns as a parameter in functions without a body. diff --git a/compiler/rustc_mir_transform/src/check_c_void.rs b/compiler/rustc_mir_transform/src/check_c_void.rs new file mode 100644 index 0000000000000..99529733d03fa --- /dev/null +++ b/compiler/rustc_mir_transform/src/check_c_void.rs @@ -0,0 +1,85 @@ +use rustc_hir::LangItem; +use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::*; +use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_session::lint::builtin::{C_VOID_REFERENCES, C_VOID_VALUES}; + +use crate::diagnostics; + +pub(super) struct CheckCVoid; + +impl<'tcx> crate::MirLint<'tcx> for CheckCVoid { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let source_info = SourceInfo::outermost(body.span); + let mut checker = CVoidChecker { body, tcx, source_info }; + checker.visit_body(body); + } +} + +struct CVoidChecker<'a, 'tcx> { + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + source_info: SourceInfo, +} + +impl<'tcx> Visitor<'tcx> for CVoidChecker<'_, 'tcx> { + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + // Make sure we know where in the MIR we are. + self.source_info = terminator.source_info; + self.super_terminator(terminator, location); + } + + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + // Make sure we know where in the MIR we are. + self.source_info = statement.source_info; + self.super_statement(statement, location); + } + + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { + match context { + PlaceContext::NonMutatingUse( + NonMutatingUseContext::Move | NonMutatingUseContext::SharedBorrow, + ) + | PlaceContext::MutatingUse( + MutatingUseContext::Store + | MutatingUseContext::AsmOutput + | MutatingUseContext::Call + | MutatingUseContext::Yield + | MutatingUseContext::Borrow, + ) => (), + _ => return, + }; + + let ty = place.ty(self.body, self.tcx).ty; + + if is_c_void(self.tcx, ty.peel_refs()) { + let Some(hir_id) = self.source_info.scope.lint_root(&self.body.source_scopes) else { + return; + }; + + if context.is_borrow() || ty.is_ref() { + self.tcx.emit_node_span_lint( + C_VOID_REFERENCES, + hir_id, + self.source_info.span, + diagnostics::CVoidRef, + ); + } else { + self.tcx.emit_node_span_lint( + C_VOID_VALUES, + hir_id, + self.source_info.span, + diagnostics::CVoidValue, + ); + } + } + } +} + +fn is_c_void(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool { + if let Some(adt_def) = ty.ty_adt_def() { + tcx.is_lang_item(adt_def.did(), LangItem::CVoid) + } else { + false + } +} diff --git a/compiler/rustc_mir_transform/src/diagnostics.rs b/compiler/rustc_mir_transform/src/diagnostics.rs index e597c10511b0f..afb0d8f0f0de5 100644 --- a/compiler/rustc_mir_transform/src/diagnostics.rs +++ b/compiler/rustc_mir_transform/src/diagnostics.rs @@ -74,6 +74,22 @@ pub(crate) struct UnalignedPackedRef { pub align: u64, } +#[derive(Diagnostic)] +#[diag("`c_void` should not be used as the referent of an `&` or `&mut` reference")] +#[help("use `&raw const` or `&raw mut` instead, to create a raw pointer")] +#[note( + "for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior" +)] +pub(crate) struct CVoidRef; + +#[derive(Diagnostic)] +#[diag("`c_void` should not be used by value")] +#[note( + "for legacy reasons, Rust considers `c_void` to have size 1, so this can cause Undefined Behavior" +)] +#[note("`c_void` is only used through raw pointers, for compatibility with `void` pointers")] +pub(crate) struct CVoidValue; + #[derive(Diagnostic)] #[diag("MIR pass `{$name}` is unknown and will be ignored")] pub(crate) struct UnknownPassName<'a> { diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 905907aa279ea..360391b4eb24c 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -131,6 +131,7 @@ declare_passes! { mod check_const_item_mutation : CheckConstItemMutation; mod check_null : CheckNull; mod check_packed_ref : CheckPackedRef; + mod check_c_void : CheckCVoid; // This pass is public to allow external drivers to perform MIR cleanup pub mod cleanup_post_borrowck : CleanupPostBorrowck; @@ -415,6 +416,7 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal> { &Lint(check_inline::CheckForceInline), &Lint(check_call_recursion::CheckCallRecursion), &Lint(check_packed_ref::CheckPackedRef), + &Lint(check_c_void::CheckCVoid), &Lint(check_const_item_mutation::CheckConstItemMutation), &Lint(function_item_references::FunctionItemReferences), // What we need to do constant evaluation. diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs index 9cca7c30817f9..c9c0238eca196 100644 --- a/src/tools/miri/src/shims/native_lib/mod.rs +++ b/src/tools/miri/src/shims/native_lib/mod.rs @@ -492,7 +492,7 @@ pub fn build_libffi_closure<'tcx, 'this>( /// As future improvement we might continue execution in the interpreter here. unsafe extern "C" fn libffi_closure_callback<'tcx>( _cif: &libffi::low::ffi_cif, - _result: &mut c_void, + _result: &mut (), _args: *const *const c_void, data: &LibffiClosureData<'tcx>, ) { diff --git a/tests/ui/lint/c-void-parameters.alias.stderr b/tests/ui/lint/c-void-parameters.alias.stderr new file mode 100644 index 0000000000000..726f4064ac137 --- /dev/null +++ b/tests/ui/lint/c-void-parameters.alias.stderr @@ -0,0 +1,43 @@ +error: `c_void` should not be used directly as the type of a function parameter + --> $DIR/c-void-parameters.rs:14:11 + | +LL | fn foo(_: c_void) { + | ^^^^^^ + | + = help: did you mean `*mut c_void` or `*const c_void`? + = note: `c_void` is only used through raw pointers, for compatibility with `void` pointers +note: the lint level is defined here + --> $DIR/c-void-parameters.rs:4:9 + | +LL | #![deny(c_void_parameters)] + | ^^^^^^^^^^^^^^^^^ + +error: `c_void` should not be used directly as the type of a function parameter + --> $DIR/c-void-parameters.rs:21:15 + | +LL | fn baz(_: c_void); + | ^^^^^^ + | + = help: did you mean `*mut c_void` or `*const c_void`? + = note: `c_void` is only used through raw pointers, for compatibility with `void` pointers + +error: `c_void` should not be used directly as the type of a function parameter + --> $DIR/c-void-parameters.rs:25:17 + | +LL | type Xyzzy = fn(c_void); + | ^^^^^^ + | + = help: did you mean `*mut c_void` or `*const c_void`? + = note: `c_void` is only used through raw pointers, for compatibility with `void` pointers + +error: `c_void` should not be used directly as the type of a function parameter + --> $DIR/c-void-parameters.rs:28:15 + | +LL | fn foo(_: c_void); + | ^^^^^^ + | + = help: did you mean `*mut c_void` or `*const c_void`? + = note: `c_void` is only used through raw pointers, for compatibility with `void` pointers + +error: aborting due to 4 previous errors + diff --git a/tests/ui/lint/c-void-parameters.direct.stderr b/tests/ui/lint/c-void-parameters.direct.stderr new file mode 100644 index 0000000000000..726f4064ac137 --- /dev/null +++ b/tests/ui/lint/c-void-parameters.direct.stderr @@ -0,0 +1,43 @@ +error: `c_void` should not be used directly as the type of a function parameter + --> $DIR/c-void-parameters.rs:14:11 + | +LL | fn foo(_: c_void) { + | ^^^^^^ + | + = help: did you mean `*mut c_void` or `*const c_void`? + = note: `c_void` is only used through raw pointers, for compatibility with `void` pointers +note: the lint level is defined here + --> $DIR/c-void-parameters.rs:4:9 + | +LL | #![deny(c_void_parameters)] + | ^^^^^^^^^^^^^^^^^ + +error: `c_void` should not be used directly as the type of a function parameter + --> $DIR/c-void-parameters.rs:21:15 + | +LL | fn baz(_: c_void); + | ^^^^^^ + | + = help: did you mean `*mut c_void` or `*const c_void`? + = note: `c_void` is only used through raw pointers, for compatibility with `void` pointers + +error: `c_void` should not be used directly as the type of a function parameter + --> $DIR/c-void-parameters.rs:25:17 + | +LL | type Xyzzy = fn(c_void); + | ^^^^^^ + | + = help: did you mean `*mut c_void` or `*const c_void`? + = note: `c_void` is only used through raw pointers, for compatibility with `void` pointers + +error: `c_void` should not be used directly as the type of a function parameter + --> $DIR/c-void-parameters.rs:28:15 + | +LL | fn foo(_: c_void); + | ^^^^^^ + | + = help: did you mean `*mut c_void` or `*const c_void`? + = note: `c_void` is only used through raw pointers, for compatibility with `void` pointers + +error: aborting due to 4 previous errors + diff --git a/tests/ui/lint/c-void-parameters.rs b/tests/ui/lint/c-void-parameters.rs new file mode 100644 index 0000000000000..5179d367ff8a2 --- /dev/null +++ b/tests/ui/lint/c-void-parameters.rs @@ -0,0 +1,31 @@ +//@ revisions: direct alias + +#![allow(unused)] +#![deny(c_void_parameters)] + +#[cfg(direct)] +use std::ffi::c_void; +#[cfg(alias)] +#[expect(non_camel_case_types)] +type c_void = std::ffi::c_void; + +use std::ptr; + +fn foo(_: c_void) { + //~^ ERROR c_void +} + +fn bar(_: *mut c_void) {} + +unsafe extern "C" { + fn baz(_: c_void); //~ ERROR c_void + fn quux(_: *const c_void); +} + +type Xyzzy = fn(c_void); //~ ERROR c_void + +trait Trait { + fn foo(_: c_void); //~ ERROR c_void +} + +fn main() {} diff --git a/tests/ui/lint/c-void-references.alias.stderr b/tests/ui/lint/c-void-references.alias.stderr new file mode 100644 index 0000000000000..5e86c2649050c --- /dev/null +++ b/tests/ui/lint/c-void-references.alias.stderr @@ -0,0 +1,89 @@ +error: `c_void` should not be used as the referent of an `&` or `&mut` reference + --> $DIR/c-void-references.rs:38:22 + | +LL | let _ = unsafe { &*raw }; + | ^^^^^ + | + = help: use `&raw const` or `&raw mut` instead, to create a raw pointer + = note: for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior +note: the lint level is defined here + --> $DIR/c-void-references.rs:4:9 + | +LL | #![deny(c_void_references)] + | ^^^^^^^^^^^^^^^^^ + +error: `c_void` should not be used as the referent of an `&` or `&mut` reference + --> $DIR/c-void-references.rs:38:22 + | +LL | let _ = unsafe { &*raw }; + | ^^^^^ + | + = help: use `&raw const` or `&raw mut` instead, to create a raw pointer + = note: for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `c_void` should not be used as the referent of an `&` or `&mut` reference + --> $DIR/c-void-references.rs:49:9 + | +LL | do_stuff_helper(raw); + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: use `&raw const` or `&raw mut` instead, to create a raw pointer + = note: for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior + +error: `c_void` should not be used as the referent of an `&` or `&mut` reference + --> $DIR/c-void-references.rs:17:13 + | +LL | fn bar() -> &'static mut c_void { + | ^^^^^^^^^^^^^^^^^^^ + | + = help: use a raw pointer, or a reference to `()`, instead + = note: for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior + +error: `c_void` should not be used as the referent of an `&` or `&mut` reference + --> $DIR/c-void-references.rs:22:20 + | +LL | fn baz() -> Option<&'static c_void> { + | ^^^^^^^^^^^^^^^ + | + = help: use a raw pointer, or a reference to `()`, instead + = note: for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior + +error: `c_void` should not be used as the referent of an `&` or `&mut` reference + --> $DIR/c-void-references.rs:27:12 + | +LL | fn quux(_: &c_void) {} + | ^^^^^^^ + | + = help: use a raw pointer, or a reference to `()`, instead + = note: for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior + +error: `c_void` should not be used as the referent of an `&` or `&mut` reference + --> $DIR/c-void-references.rs:29:16 + | +LL | type Boo<'a> = &'a c_void; + | ^^^^^^^^^^ + | + = help: use a raw pointer, or a reference to `()`, instead + = note: for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior + +error: `c_void` should not be used as the referent of an `&` or `&mut` reference + --> $DIR/c-void-references.rs:34:20 + | +LL | impl<'a> Trait for &'a c_void {} + | ^^^^^^^^^^ + | + = help: use a raw pointer, or a reference to `()`, instead + = note: for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior + +error: `c_void` should not be used as the referent of an `&` or `&mut` reference + --> $DIR/c-void-references.rs:55:12 + | +LL | let _: &'static c_void = panic!(); + | ^^^^^^^^^^^^^^^ + | + = help: use a raw pointer, or a reference to `()`, instead + = note: for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior + +error: aborting due to 9 previous errors + diff --git a/tests/ui/lint/c-void-references.direct.stderr b/tests/ui/lint/c-void-references.direct.stderr new file mode 100644 index 0000000000000..5e86c2649050c --- /dev/null +++ b/tests/ui/lint/c-void-references.direct.stderr @@ -0,0 +1,89 @@ +error: `c_void` should not be used as the referent of an `&` or `&mut` reference + --> $DIR/c-void-references.rs:38:22 + | +LL | let _ = unsafe { &*raw }; + | ^^^^^ + | + = help: use `&raw const` or `&raw mut` instead, to create a raw pointer + = note: for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior +note: the lint level is defined here + --> $DIR/c-void-references.rs:4:9 + | +LL | #![deny(c_void_references)] + | ^^^^^^^^^^^^^^^^^ + +error: `c_void` should not be used as the referent of an `&` or `&mut` reference + --> $DIR/c-void-references.rs:38:22 + | +LL | let _ = unsafe { &*raw }; + | ^^^^^ + | + = help: use `&raw const` or `&raw mut` instead, to create a raw pointer + = note: for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `c_void` should not be used as the referent of an `&` or `&mut` reference + --> $DIR/c-void-references.rs:49:9 + | +LL | do_stuff_helper(raw); + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: use `&raw const` or `&raw mut` instead, to create a raw pointer + = note: for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior + +error: `c_void` should not be used as the referent of an `&` or `&mut` reference + --> $DIR/c-void-references.rs:17:13 + | +LL | fn bar() -> &'static mut c_void { + | ^^^^^^^^^^^^^^^^^^^ + | + = help: use a raw pointer, or a reference to `()`, instead + = note: for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior + +error: `c_void` should not be used as the referent of an `&` or `&mut` reference + --> $DIR/c-void-references.rs:22:20 + | +LL | fn baz() -> Option<&'static c_void> { + | ^^^^^^^^^^^^^^^ + | + = help: use a raw pointer, or a reference to `()`, instead + = note: for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior + +error: `c_void` should not be used as the referent of an `&` or `&mut` reference + --> $DIR/c-void-references.rs:27:12 + | +LL | fn quux(_: &c_void) {} + | ^^^^^^^ + | + = help: use a raw pointer, or a reference to `()`, instead + = note: for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior + +error: `c_void` should not be used as the referent of an `&` or `&mut` reference + --> $DIR/c-void-references.rs:29:16 + | +LL | type Boo<'a> = &'a c_void; + | ^^^^^^^^^^ + | + = help: use a raw pointer, or a reference to `()`, instead + = note: for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior + +error: `c_void` should not be used as the referent of an `&` or `&mut` reference + --> $DIR/c-void-references.rs:34:20 + | +LL | impl<'a> Trait for &'a c_void {} + | ^^^^^^^^^^ + | + = help: use a raw pointer, or a reference to `()`, instead + = note: for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior + +error: `c_void` should not be used as the referent of an `&` or `&mut` reference + --> $DIR/c-void-references.rs:55:12 + | +LL | let _: &'static c_void = panic!(); + | ^^^^^^^^^^^^^^^ + | + = help: use a raw pointer, or a reference to `()`, instead + = note: for legacy reasons, Rust considers `c_void` to have size 1, so references to it can cause Undefined Behavior + +error: aborting due to 9 previous errors + diff --git a/tests/ui/lint/c-void-references.rs b/tests/ui/lint/c-void-references.rs new file mode 100644 index 0000000000000..9c83194ae815f --- /dev/null +++ b/tests/ui/lint/c-void-references.rs @@ -0,0 +1,57 @@ +//@ revisions: direct alias + +#![allow(unused)] +#![deny(c_void_references)] + +#[cfg(direct)] +use std::ffi::c_void; +#[cfg(alias)] +#[expect(non_camel_case_types)] +type c_void = std::ffi::c_void; + +fn foo() -> *mut c_void { + // fine + std::ptr::null_mut() +} + +fn bar() -> &'static mut c_void { + //~^ ERROR c_void + panic!(); +} + +fn baz() -> Option<&'static c_void> { + //~^ ERROR c_void + None +} + +fn quux(_: &c_void) {} //~ ERROR c_void + +type Boo<'a> = &'a c_void; +//~^ ERROR c_void + +trait Trait {} + +impl<'a> Trait for &'a c_void {} +//~^ ERROR c_void + +fn do_stuff(raw: *mut c_void) { + let _ = unsafe { &*raw }; + //~^ ERROR c_void + //~| ERROR c_void +} + +unsafe fn do_stuff_helper<'a, T>(raw: *mut T) -> &'a T { + unsafe { &*raw } +} + +fn do_stuff_2(raw: *mut c_void) { + unsafe { + do_stuff_helper(raw); + //~^ ERROR c_void + } +} + +fn main() { + let _: &'static c_void = panic!(); + //~^ ERROR c_void +} diff --git a/tests/ui/lint/c-void-returns.stderr b/tests/ui/lint/c-void-returns.alias.stderr similarity index 62% rename from tests/ui/lint/c-void-returns.stderr rename to tests/ui/lint/c-void-returns.alias.stderr index 7dc724955ecb4..3f593e8d7cb2f 100644 --- a/tests/ui/lint/c-void-returns.stderr +++ b/tests/ui/lint/c-void-returns.alias.stderr @@ -1,5 +1,5 @@ error: `c_void` should not be used as a return type - --> $DIR/c-void-returns.rs:7:13 + --> $DIR/c-void-returns.rs:14:13 | LL | fn foo() -> c_void { | ----^^^^^^ @@ -8,13 +8,13 @@ LL | fn foo() -> c_void { | = help: returning `()` in Rust is equivalent to returning `void` in C note: the lint level is defined here - --> $DIR/c-void-returns.rs:2:9 + --> $DIR/c-void-returns.rs:4:9 | LL | #![deny(c_void_returns)] | ^^^^^^^^^^^^^^ error: declarations returning `c_void` are not compatible with C functions returning `void` - --> $DIR/c-void-returns.rs:16:17 + --> $DIR/c-void-returns.rs:24:17 | LL | fn baz() -> c_void; | ----^^^^^^ @@ -22,10 +22,10 @@ LL | fn baz() -> c_void; | help: remove the return type to implicitly return `()` | = help: returning `()` in Rust is equivalent to returning `void` in C - = note: `c_void` is only used through raw pointers for compatibility with `void` pointers + = note: `c_void` is only used through raw pointers, for compatibility with `void` pointers error: `c_void` should not be used as a return type - --> $DIR/c-void-returns.rs:20:22 + --> $DIR/c-void-returns.rs:28:22 | LL | type Xyzzy = fn() -> c_void; | ----^^^^^^ @@ -34,5 +34,15 @@ LL | type Xyzzy = fn() -> c_void; | = help: returning `()` in Rust is equivalent to returning `void` in C -error: aborting due to 3 previous errors +error: `c_void` should not be used as a return type + --> $DIR/c-void-returns.rs:31:17 + | +LL | fn foo() -> c_void; + | ----^^^^^^ + | | + | help: remove the return type to implicitly return `()` + | + = help: returning `()` in Rust is equivalent to returning `void` in C + +error: aborting due to 4 previous errors diff --git a/tests/ui/lint/c-void-returns.direct.stderr b/tests/ui/lint/c-void-returns.direct.stderr new file mode 100644 index 0000000000000..3f593e8d7cb2f --- /dev/null +++ b/tests/ui/lint/c-void-returns.direct.stderr @@ -0,0 +1,48 @@ +error: `c_void` should not be used as a return type + --> $DIR/c-void-returns.rs:14:13 + | +LL | fn foo() -> c_void { + | ----^^^^^^ + | | + | help: remove the return type to implicitly return `()` + | + = help: returning `()` in Rust is equivalent to returning `void` in C +note: the lint level is defined here + --> $DIR/c-void-returns.rs:4:9 + | +LL | #![deny(c_void_returns)] + | ^^^^^^^^^^^^^^ + +error: declarations returning `c_void` are not compatible with C functions returning `void` + --> $DIR/c-void-returns.rs:24:17 + | +LL | fn baz() -> c_void; + | ----^^^^^^ + | | + | help: remove the return type to implicitly return `()` + | + = help: returning `()` in Rust is equivalent to returning `void` in C + = note: `c_void` is only used through raw pointers, for compatibility with `void` pointers + +error: `c_void` should not be used as a return type + --> $DIR/c-void-returns.rs:28:22 + | +LL | type Xyzzy = fn() -> c_void; + | ----^^^^^^ + | | + | help: remove the return type to implicitly return `()` + | + = help: returning `()` in Rust is equivalent to returning `void` in C + +error: `c_void` should not be used as a return type + --> $DIR/c-void-returns.rs:31:17 + | +LL | fn foo() -> c_void; + | ----^^^^^^ + | | + | help: remove the return type to implicitly return `()` + | + = help: returning `()` in Rust is equivalent to returning `void` in C + +error: aborting due to 4 previous errors + diff --git a/tests/ui/lint/c-void-returns.rs b/tests/ui/lint/c-void-returns.rs index 7531da3d72f41..d6eb5a2076331 100644 --- a/tests/ui/lint/c-void-returns.rs +++ b/tests/ui/lint/c-void-returns.rs @@ -1,10 +1,18 @@ +//@ revisions: direct alias + #![allow(unused)] #![deny(c_void_returns)] +#[cfg(direct)] use std::ffi::c_void; +#[cfg(alias)] +#[expect(non_camel_case_types)] +type c_void = std::ffi::c_void; + use std::ptr; -fn foo() -> c_void { //~ ERROR c_void +fn foo() -> c_void { + //~^ ERROR c_void unreachable!() } @@ -19,4 +27,8 @@ unsafe extern "C" { type Xyzzy = fn() -> c_void; //~ ERROR c_void +trait Trait { + fn foo() -> c_void; //~ ERROR c_void +} + fn main() {} diff --git a/tests/ui/lint/c-void-statics.alias.stderr b/tests/ui/lint/c-void-statics.alias.stderr new file mode 100644 index 0000000000000..21e85892fbfe3 --- /dev/null +++ b/tests/ui/lint/c-void-statics.alias.stderr @@ -0,0 +1,45 @@ +error: `const` items should not have type `c_void` + --> $DIR/c-void-statics.rs:13:1 + | +LL | const FOO: c_void = unsafe { std::mem::transmute(0u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `c_void` is only used through raw pointers, for compatibility with C `void` pointers +note: the lint level is defined here + --> $DIR/c-void-statics.rs:4:9 + | +LL | #![deny(c_void_statics)] + | ^^^^^^^^^^^^^^ + +error: `static` items should not have type `c_void` + --> $DIR/c-void-statics.rs:15:1 + | +LL | static BAR: c_void = unsafe { std::mem::transmute(0u8) }; + | ^^^^^^^^^^^^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: use `()` instead: `()` + | + = help: for a `static` used only for its address, use `()` instead + = note: `c_void` is only used through raw pointers, for compatibility with C `void` pointers + +error: `static` items should not have type `c_void` + --> $DIR/c-void-statics.rs:19:5 + | +LL | safe static BAZ: c_void; + | ^^^^^^^^^^^^^^^^^------^ + | | + | help: use `()` instead: `()` + | + = help: for a `static` used only for its address, use `()` instead + = note: `c_void` is only used through raw pointers, for compatibility with C `void` pointers + +error: `const` items should not have type `c_void` + --> $DIR/c-void-statics.rs:24:5 + | +LL | const FOO: c_void; + | ^^^^^^^^^^^^^^^^^^ + | + = note: `c_void` is only used through raw pointers, for compatibility with C `void` pointers + +error: aborting due to 4 previous errors + diff --git a/tests/ui/lint/c-void-statics.direct.stderr b/tests/ui/lint/c-void-statics.direct.stderr new file mode 100644 index 0000000000000..21e85892fbfe3 --- /dev/null +++ b/tests/ui/lint/c-void-statics.direct.stderr @@ -0,0 +1,45 @@ +error: `const` items should not have type `c_void` + --> $DIR/c-void-statics.rs:13:1 + | +LL | const FOO: c_void = unsafe { std::mem::transmute(0u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `c_void` is only used through raw pointers, for compatibility with C `void` pointers +note: the lint level is defined here + --> $DIR/c-void-statics.rs:4:9 + | +LL | #![deny(c_void_statics)] + | ^^^^^^^^^^^^^^ + +error: `static` items should not have type `c_void` + --> $DIR/c-void-statics.rs:15:1 + | +LL | static BAR: c_void = unsafe { std::mem::transmute(0u8) }; + | ^^^^^^^^^^^^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: use `()` instead: `()` + | + = help: for a `static` used only for its address, use `()` instead + = note: `c_void` is only used through raw pointers, for compatibility with C `void` pointers + +error: `static` items should not have type `c_void` + --> $DIR/c-void-statics.rs:19:5 + | +LL | safe static BAZ: c_void; + | ^^^^^^^^^^^^^^^^^------^ + | | + | help: use `()` instead: `()` + | + = help: for a `static` used only for its address, use `()` instead + = note: `c_void` is only used through raw pointers, for compatibility with C `void` pointers + +error: `const` items should not have type `c_void` + --> $DIR/c-void-statics.rs:24:5 + | +LL | const FOO: c_void; + | ^^^^^^^^^^^^^^^^^^ + | + = note: `c_void` is only used through raw pointers, for compatibility with C `void` pointers + +error: aborting due to 4 previous errors + diff --git a/tests/ui/lint/c-void-statics.rs b/tests/ui/lint/c-void-statics.rs new file mode 100644 index 0000000000000..68905a6ea9148 --- /dev/null +++ b/tests/ui/lint/c-void-statics.rs @@ -0,0 +1,28 @@ +//@ revisions: direct alias + +#![allow(unused)] +#![deny(c_void_statics)] +#![allow(c_void_values)] + +#[cfg(direct)] +use std::ffi::c_void; +#[cfg(alias)] +#[expect(non_camel_case_types)] +type c_void = std::ffi::c_void; + +const FOO: c_void = unsafe { std::mem::transmute(0u8) }; +//~^ ERROR c_void +static BAR: c_void = unsafe { std::mem::transmute(0u8) }; +//~^ ERROR c_void + +unsafe extern "C" { + safe static BAZ: c_void; + //~^ ERROR c_void +} + +trait Trait { + const FOO: c_void; + //~^ ERROR c_void +} + +fn main() {} diff --git a/tests/ui/lint/c-void-values.alias.stderr b/tests/ui/lint/c-void-values.alias.stderr new file mode 100644 index 0000000000000..ce9022a7c3c93 --- /dev/null +++ b/tests/ui/lint/c-void-values.alias.stderr @@ -0,0 +1,34 @@ +error: `c_void` should not be used by value + --> $DIR/c-void-values.rs:13:30 + | +LL | const FOO: c_void = unsafe { std::mem::transmute(0u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for legacy reasons, Rust considers `c_void` to have size 1, so this can cause Undefined Behavior + = note: `c_void` is only used through raw pointers, for compatibility with `void` pointers +note: the lint level is defined here + --> $DIR/c-void-values.rs:4:9 + | +LL | #![deny(c_void_values)] + | ^^^^^^^^^^^^^ + +error: `c_void` should not be used by value + --> $DIR/c-void-values.rs:15:31 + | +LL | static BAR: c_void = unsafe { std::mem::transmute(0u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for legacy reasons, Rust considers `c_void` to have size 1, so this can cause Undefined Behavior + = note: `c_void` is only used through raw pointers, for compatibility with `void` pointers + +error: `c_void` should not be used by value + --> $DIR/c-void-values.rs:19:14 + | +LL | unsafe { r.read() }; + | ^^^^^^^^ + | + = note: for legacy reasons, Rust considers `c_void` to have size 1, so this can cause Undefined Behavior + = note: `c_void` is only used through raw pointers, for compatibility with `void` pointers + +error: aborting due to 3 previous errors + diff --git a/tests/ui/lint/c-void-values.direct.stderr b/tests/ui/lint/c-void-values.direct.stderr new file mode 100644 index 0000000000000..ce9022a7c3c93 --- /dev/null +++ b/tests/ui/lint/c-void-values.direct.stderr @@ -0,0 +1,34 @@ +error: `c_void` should not be used by value + --> $DIR/c-void-values.rs:13:30 + | +LL | const FOO: c_void = unsafe { std::mem::transmute(0u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for legacy reasons, Rust considers `c_void` to have size 1, so this can cause Undefined Behavior + = note: `c_void` is only used through raw pointers, for compatibility with `void` pointers +note: the lint level is defined here + --> $DIR/c-void-values.rs:4:9 + | +LL | #![deny(c_void_values)] + | ^^^^^^^^^^^^^ + +error: `c_void` should not be used by value + --> $DIR/c-void-values.rs:15:31 + | +LL | static BAR: c_void = unsafe { std::mem::transmute(0u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for legacy reasons, Rust considers `c_void` to have size 1, so this can cause Undefined Behavior + = note: `c_void` is only used through raw pointers, for compatibility with `void` pointers + +error: `c_void` should not be used by value + --> $DIR/c-void-values.rs:19:14 + | +LL | unsafe { r.read() }; + | ^^^^^^^^ + | + = note: for legacy reasons, Rust considers `c_void` to have size 1, so this can cause Undefined Behavior + = note: `c_void` is only used through raw pointers, for compatibility with `void` pointers + +error: aborting due to 3 previous errors + diff --git a/tests/ui/lint/c-void-values.rs b/tests/ui/lint/c-void-values.rs new file mode 100644 index 0000000000000..26d4d968884cd --- /dev/null +++ b/tests/ui/lint/c-void-values.rs @@ -0,0 +1,23 @@ +//@ revisions: direct alias + +#![allow(unused)] +#![deny(c_void_values)] +#![allow(c_void_statics)] + +#[cfg(direct)] +use std::ffi::c_void; +#[cfg(alias)] +#[expect(non_camel_case_types)] +type c_void = std::ffi::c_void; + +const FOO: c_void = unsafe { std::mem::transmute(0u8) }; +//~^ ERROR c_void +static BAR: c_void = unsafe { std::mem::transmute(0u8) }; +//~^ ERROR c_void + +fn foo(r: *mut c_void) { + unsafe { r.read() }; + //~^ ERROR c_void +} + +fn main() {}