`improper_ctypes_definitions` is sometimes (but not always) bypassed by cross-crate macros
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
Code
// Crate 1, rust_ffi_hax_test
#[macro_export]
macro_rules! test_macro {
() => {
#[unsafe(no_mangle)]
extern "C" fn make_struct(a: bool, b: *const ()) -> SomeRustStruct {
SomeRustStruct {
a: if a { Some(b) } else { None },
}
}
};
}
// Crate 2, rust_ffi_hax_test_2
#[derive(Debug)]
pub struct SomeRustStruct {
pub a: Option<*const ()>,
}
::rust_ffi_hax_test::test_macro!();
// #[unsafe(no_mangle)]
// extern "C" fn make_struct(a: bool, b: *const ()) -> SomeRustStruct {
// SomeRustStruct {
// a: if a { Some(b) } else { None },
// }
// }
Current output
Nothing (no warning) is printed, unless the macro is replaced with the commented-out expansion of the macro, in which case the usual warning is printed:
warning: `extern` fn uses type `SomeRustStruct`, which is not FFI-safe
--> rust-ffi-hax-test-2/src/lib.rs:8:53
|
8 | extern "C" fn make_struct(a: bool, b: *const ()) -> SomeRustStruct {
| ^^^^^^^^^^^^^^ not FFI-safe
|
= 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
--> rust-ffi-hax-test-2/src/lib.rs:2:1
|
2 | pub struct SomeRustStruct {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: `#[warn(improper_ctypes_definitions)]` on by default
Desired output
Either the type is FFI-safe or it isn't, right? I would expect that putting the extern "C" function inside a macro in another crate should not change this property.
Rationale and extra context
I am trying to write FFI bindings where Rust objects are returned to C++ code, where the C++ code knows the size and alignment of the Rust object but knows nothing about the contents. I thought I had gotten it right (the size and alignment do match, and there are no warnings!), but I stumbled into an issue with the (Itanium C++ ABI) "non-trivial for the purposes of calls" property.
Since this is a C++ property, clang can catch it, even when Rust doesn't:
test.cpp:13:28: warning: 'make_struct' has C-linkage specified, but returns user-defined type 'RustStructDummy' which is incompatible with C [-Wreturn-type-c-linkage]
Other cases
I encountered situations where this warning still fires cross-crate, but I haven't figured out why it happens sometimes (in a more complicated situation!) but not in this simple example.
Rust Version
$ rustc --version --verbose
rustc 1.97.1 (8bab26f4f 2026-07-14)
binary: rustc
commit-hash: 8bab26f4f68e0e26f0bb7960be334d5b520ea452
commit-date: 2026-07-14
host: aarch64-apple-darwin
release: 1.97.1
LLVM version: 22.1.6
Anything else?
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the two-crate example using rust-ffi-hax-test-2/src/lib.rs, comparing the cross-crate macro invocation with its commented-out expansion. Start by tracing how the improper_ctypes_definitions lint handles macro-expanded extern functions; done means the cross-crate case consistently reports the same FFI-safety warning as the direct expansion.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100