rustc_lint/
c_void_returns.rs1use rustc_abi::ExternAbi;
2use rustc_hir::def::Res;
3use rustc_hir::def_id::LocalDefId;
4use rustc_hir::intravisit::FnKind;
5use rustc_hir::{self as hir, LangItem};
6use rustc_session::{declare_lint, declare_lint_pass};
7use rustc_span::Span;
8
9use crate::lints::{CVoidReturn, ExternCVoidReturn};
10use crate::{LateContext, LateLintPass, LintContext};
11
12#[doc =
r" The `c_void_returns` lint detects the use of [`core::ffi::c_void`] as a return type."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust"]
#[doc = r" use std::ffi::c_void;"]
#[doc = r""]
#[doc = r#" unsafe extern "C" {"#]
#[doc = r" fn foo() -> c_void;"]
#[doc = r" }"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc =
r" `c_void` is designed for use through a [`pointer`], equivalent to C's `void*` type. It is a"]
#[doc =
r" mistake to use it directly as a return type, and calling `extern` functions declared as such"]
#[doc =
r" may result in undefined behavior. C functions that return `void` must be declared to return"]
#[doc =
r" [`()`] in Rust (omitting the return type implicitly returns `()`)."]
#[doc = r""]
#[doc =
r" [`core::ffi::c_void`]: https://doc.rust-lang.org/core/ffi/enum.c_void.html"]
#[doc =
r" [`pointer`]: https://doc.rust-lang.org/core/primitive.pointer.html"]
#[doc = r" [`()`]: https://doc.rust-lang.org/core/primitive.unit.html"]
pub static C_VOID_RETURNS: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: "C_VOID_RETURNS",
default_level: ::rustc_lint_defs::Warn,
desc: "detects use of `c_void` as a return type",
is_externally_loaded: false,
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_lint! {
13 pub C_VOID_RETURNS,
38 Warn,
39 "detects use of `c_void` as a return type"
40}
41
42pub struct CVoidReturns;
#[automatically_derived]
impl ::core::marker::Copy for CVoidReturns { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for CVoidReturns { }
#[automatically_derived]
impl ::core::clone::Clone for CVoidReturns {
#[inline]
fn clone(&self) -> CVoidReturns { *self }
}
impl ::rustc_lint_defs::LintPass for CVoidReturns {
fn name(&self) -> &'static str { "CVoidReturns" }
fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[C_VOID_RETURNS]))
}
}
impl CVoidReturns {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[C_VOID_RETURNS]))
}
}declare_lint_pass!(CVoidReturns => [C_VOID_RETURNS]);
43
44impl<'tcx> LateLintPass<'tcx> for CVoidReturns {
45 fn check_fn(
46 &mut self,
47 cx: &LateContext<'tcx>,
48 fn_kind: FnKind<'tcx>,
49 decl: &'tcx hir::FnDecl<'tcx>,
50 _: &'tcx hir::Body<'tcx>,
51 _: Span,
52 _: LocalDefId,
53 ) {
54 check_decl(
55 cx,
56 decl,
57 !#[allow(non_exhaustive_omitted_patterns)] match fn_kind {
FnKind::ItemFn(.., hir::FnHeader { abi: ExternAbi::Rust, .. }) => true,
_ => false,
}matches!(fn_kind, FnKind::ItemFn(.., hir::FnHeader { abi: ExternAbi::Rust, .. })),
58 );
59 }
60
61 fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ForeignItem<'tcx>) {
62 if let hir::ForeignItemKind::Fn(sig, ..) = item.kind {
63 check_decl(cx, sig.decl, true);
64 }
65 }
66
67 fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx, hir::AmbigArg>) {
68 if let hir::TyKind::FnPtr(fn_ptr_ty) = ty.kind {
69 check_decl(cx, fn_ptr_ty.decl, fn_ptr_ty.abi != ExternAbi::Rust);
70 }
71 }
72}
73
74fn check_decl(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, is_extern: bool) {
75 if let hir::FnRetTy::Return(output_ty) = decl.output
76 && let hir::TyKind::Path(qpath) = output_ty.kind
77 && let Res::Def(.., def_id) = cx.qpath_res(&qpath, output_ty.hir_id)
78 && cx.tcx.is_lang_item(def_id, LangItem::CVoid)
79 {
80 let suggestion =
81 cx.sess().source_map().span_extend_to_prev_char(decl.output.span(), ')', true);
82
83 if is_extern {
84 cx.emit_span_lint(C_VOID_RETURNS, decl.output.span(), ExternCVoidReturn { suggestion });
85 } else {
86 cx.emit_span_lint(C_VOID_RETURNS, decl.output.span(), CVoidReturn { suggestion });
87 }
88 }
89}