Skip to content

clippy::missing_safety_doc triggers on cxx::bridge-generated code #16317

Closed

Description

@anforowicz

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

Activity

  1. added
    C-bugCategory: Clippy is not doing the correct thing
    I-false-positiveIssue: The lint was triggered on code it shouldn't have
    on Dec 31, 2025
  2. added a commit that references this issue on Sep 3, 2026
    0fcb239
  3. andogq commented on Sep 3, 2026

    @andogq
    Contributor

    @rustbot claim

  4. added a commit that references this issue on Sep 23, 2026
    a083651
  5. added a commit that references this issue on Sep 29, 2026
    783e510
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

C-bugCategory: Clippy is not doing the correct thingI-false-positiveIssue: The lint was triggered on code it shouldn't have

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions