-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Open
Labels
C-bugCategory: Clippy is not doing the correct thingCategory: Clippy is not doing the correct thingI-false-positiveIssue: The lint was triggered on code it shouldn't haveIssue: The lint was triggered on code it shouldn't have
Description
Summary
It seems that missing_safety_doc triggers on pub unsafe fn my_fn generated by cxx::bridge, even though the macro expansion does contain a safety doc.
PS. At first glance this seems similar to #4949, but in the other bug the macro expansion did not propagate the safety doc.
Lint Name
missing_safety_doc
Reproducer
I tried this code:
// src/lib.rs:
#![deny(clippy::missing_safety_doc)]
#[cxx::bridge]
pub mod ffi {
unsafe extern "C++" {
type R;
/// # Safety
///
/// Caller needs to ensure that X, Y, Z.
unsafe fn my_fn(&self);
}
}
pub fn public_my_fn(r: &ffi::R) {
// SAFETY: X, Y, and Z are guaranteed based on ...
unsafe { r.my_fn() }
}# Cargo.toml:
[package]
name = "clippy-cxx-missing-safety-doc-repro"
version = "0.1.0"
edition = "2024"
[dependencies]
cxx = "1.0.192"
[lib]
I saw this happen:
$ cargo clippy
Checking clippy-cxx-missing-safety-doc-repro v0.1.0 (/usr/local/google/home/lukasza/src/cargo/clippy-cxx-missing-safety-doc-repro)
error: unsafe function's docs are missing a `# Safety` section
--> src/lib.rs:11:9
|
11 | unsafe fn my_fn(&self);
| ^^^^^^^^^^^^^^^^^^^^^^
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc
note: the lint level is defined here
--> src/lib.rs:1:9
|
1 | #![deny(clippy::missing_safety_doc)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: could not compile `clippy-cxx-missing-safety-doc-repro` (lib) due to 1 previous error
I expected to see no errors/warnings, because the proc macro expansion preserves the doc comment as follows:
$ cargo expand
Checking clippy-cxx-missing-safety-doc-repro v0.1.0 (/usr/local/google/home/lukasza/src/cargo/clippy-cxx-missing-safety-doc-repro)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.06s
#![feature(prelude_import)]
#![deny(clippy::missing_safety_doc)]
#[macro_use]
extern crate std;
#[prelude_import]
use std::prelude::rust_2024::*;
#[deny(improper_ctypes, improper_ctypes_definitions)]
#[allow(clippy::unknown_lints)]
#[allow(
non_camel_case_types,
non_snake_case,
clippy::extra_unused_type_parameters,
clippy::items_after_statements,
clippy::no_effect_underscore_binding,
clippy::unsafe_derive_deserialize,
clippy::upper_case_acronyms,
clippy::use_self,
)]
pub mod ffi {
#[repr(C)]
pub struct R {
_private: ::cxx::private::Opaque,
}
#[automatically_derived]
unsafe impl ::cxx::ExternType for R {
#[allow(unused_attributes)]
#[doc(hidden)]
type Id = (::cxx::R,);
type Kind = ::cxx::kind::Opaque;
}
impl R {
/// # Safety
///
/// Caller needs to ensure that X, Y, Z.
pub unsafe fn my_fn(&self) {
unsafe extern "C" {
#[link_name = "cxxbridge1$192$R$my_fn"]
fn __my_fn(_: &R);
}
unsafe {
__my_fn(self);
}
}
}
#[doc(hidden)]
const _: () = {
let _: fn() = {
trait __AmbiguousIfImpl<A> {
fn infer() {}
}
#[automatically_derived]
impl<T> __AmbiguousIfImpl<()> for T
where
T: ?::cxx::core::marker::Sized,
{}
#[allow(dead_code)]
struct __Invalid;
#[automatically_derived]
impl<T> __AmbiguousIfImpl<__Invalid> for T
where
T: ?::cxx::core::marker::Sized + ::cxx::core::marker::Unpin,
{}
<R as __AmbiguousIfImpl<_>>::infer
};
};
}
pub fn public_my_fn(r: &ffi::R) {
unsafe { r.my_fn() }
}
Version
$ rustc -Vv
rustc 1.94.0-nightly (0208ee09b 2025-12-14)
binary: rustc
commit-hash: 0208ee09be465f69005a7a12c28d5eccac7d5f34
commit-date: 2025-12-14
host: x86_64-unknown-linux-gnu
release: 1.94.0-nightly
LLVM version: 21.1.5
$ clippy-driver --version
clippy 0.1.94 (0208ee09be 2025-12-14)
Additional Labels
No response
Metadata
Metadata
Assignees
Labels
C-bugCategory: Clippy is not doing the correct thingCategory: Clippy is not doing the correct thingI-false-positiveIssue: The lint was triggered on code it shouldn't haveIssue: The lint was triggered on code it shouldn't have