Skip to content

Commit c9a0ac1

Browse files
authored
Rollup merge of rust-lang#146521 - folkertdev:document-va-arg-safe, r=workingjubilee
document `core::ffi::VaArgSafe` tracking issue: rust-lang#44930 A modification of rust-lang#146454, keeping just the documentation changes, but not unsealing the trait. Although conceptually we'd want to unseal the trait, there are many edge cases to supporting arbitrary types. We'd need to exhaustively test that all targets/calling conventions support all types that rust might generate (or generate proper error messages for unsupported cases). At present, many of the `va_arg` implementations assume that the argument is a scalar, and has an alignment of at most 8. That is totally sufficient for an MVP (accepting all of the "standard" C types), but clearly does not cover all rust types. This PR also adds some various other tests for edge cases of c-variadic: - the `#[inline]` attribute in its various forms. At present, LLVM is unable to inline c-variadic functions, but the attribute should still be accepted. `#[rustc_force_inline]` already rejects c-variadic functions. - naked functions should accept and work with a C variable argument list. In the future we'd like to allow more ABIs with naked functions (basically, any ABI for which we accept defining foreign c-variadic functions), but for now only `"C"` and `"C-unwind` are supported - guaranteed tail calls: c-variadic functions cannot be tail-called. That was already rejected, but there was not test for it. r? `@workingjubilee`
2 parents c612214 + f580b96 commit c9a0ac1

File tree

1 file changed

+23
-6
lines changed

1 file changed

+23
-6
lines changed

core/src/ffi/va_list.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -202,18 +202,23 @@ mod sealed {
202202
impl<T> Sealed for *const T {}
203203
}
204204

205-
/// Trait which permits the allowed types to be used with [`VaListImpl::arg`].
205+
/// Types that are valid to read using [`VaListImpl::arg`].
206206
///
207207
/// # Safety
208208
///
209-
/// This trait must only be implemented for types that C passes as varargs without implicit promotion.
209+
/// The standard library implements this trait for primitive types that are
210+
/// expected to have a variable argument application-binary interface (ABI) on all
211+
/// platforms.
210212
///
211-
/// In C varargs, integers smaller than [`c_int`] and floats smaller than [`c_double`]
212-
/// are implicitly promoted to [`c_int`] and [`c_double`] respectively. Implementing this trait for
213-
/// types that are subject to this promotion rule is invalid.
213+
/// When C passes variable arguments, integers smaller than [`c_int`] and floats smaller
214+
/// than [`c_double`] are implicitly promoted to [`c_int`] and [`c_double`] respectively.
215+
/// Implementing this trait for types that are subject to this promotion rule is invalid.
214216
///
215217
/// [`c_int`]: core::ffi::c_int
216218
/// [`c_double`]: core::ffi::c_double
219+
// We may unseal this trait in the future, but currently our `va_arg` implementations don't support
220+
// types with an alignment larger than 8, or with a non-scalar layout. Inline assembly can be used
221+
// to accept unsupported types in the meantime.
217222
pub unsafe trait VaArgSafe: sealed::Sealed {}
218223

219224
// i8 and i16 are implicitly promoted to c_int in C, and cannot implement `VaArgSafe`.
@@ -233,7 +238,19 @@ unsafe impl<T> VaArgSafe for *mut T {}
233238
unsafe impl<T> VaArgSafe for *const T {}
234239

235240
impl<'f> VaListImpl<'f> {
236-
/// Advance to the next arg.
241+
/// Advance to and read the next variable argument.
242+
///
243+
/// # Safety
244+
///
245+
/// This function is only sound to call when the next variable argument:
246+
///
247+
/// - has a type that is ABI-compatible with the type `T`
248+
/// - has a value that is a properly initialized value of type `T`
249+
///
250+
/// Calling this function with an incompatible type, an invalid value, or when there
251+
/// are no more variable arguments, is unsound.
252+
///
253+
/// [valid]: https://doc.rust-lang.org/nightly/nomicon/what-unsafe-does.html
237254
#[inline]
238255
pub unsafe fn arg<T: VaArgSafe>(&mut self) -> T {
239256
// SAFETY: the caller must uphold the safety contract for `va_arg`.

0 commit comments

Comments
 (0)