@@ -223,39 +223,57 @@ impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> {
223223 }
224224}
225225
226- // The VaArgSafe trait needs to be used in public interfaces, however, the trait
227- // itself must not be allowed to be used outside this module. Allowing users to
228- // implement the trait for a new type (thereby allowing the va_arg intrinsic to
229- // be used on a new type) is likely to cause undefined behavior.
230- //
231- // FIXME(dlrobertson): In order to use the VaArgSafe trait in a public interface
232- // but also ensure it cannot be used elsewhere, the trait needs to be public
233- // within a private module. Once RFC 2145 has been implemented look into
234- // improving this.
235- mod sealed_trait {
236- /// Trait which permits the allowed types to be used with [super::VaListImpl::arg].
237- pub unsafe trait VaArgSafe { }
238- }
226+ mod sealed {
227+ pub trait Sealed { }
239228
240- macro_rules! impl_va_arg_safe {
241- ( $( $t: ty) ,+) => {
242- $(
243- unsafe impl sealed_trait:: VaArgSafe for $t { }
244- ) +
245- }
229+ impl Sealed for i32 { }
230+ impl Sealed for i64 { }
231+ impl Sealed for isize { }
232+
233+ impl Sealed for u32 { }
234+ impl Sealed for u64 { }
235+ impl Sealed for usize { }
236+
237+ impl Sealed for f64 { }
238+
239+ impl < T > Sealed for * mut T { }
240+ impl < T > Sealed for * const T { }
246241}
247242
248- impl_va_arg_safe ! { i8 , i16 , i32 , i64 , usize }
249- impl_va_arg_safe ! { u8 , u16 , u32 , u64 , isize }
250- impl_va_arg_safe ! { f64 }
243+ /// Trait which permits the allowed types to be used with [`VaListImpl::arg`].
244+ ///
245+ /// # Safety
246+ ///
247+ /// This trait must only be implemented for types that C passes as varargs without implicit promotion.
248+ ///
249+ /// In C varargs, integers smaller than [`c_int`] and floats smaller than [`c_double`]
250+ /// are implicitly promoted to [`c_int`] and [`c_double`] respectively. Implementing this trait for
251+ /// types that are subject to this promotion rule is invalid.
252+ ///
253+ /// [`c_int`]: core::ffi::c_int
254+ /// [`c_double`]: core::ffi::c_double
255+ pub unsafe trait VaArgSafe : sealed:: Sealed { }
256+
257+ // i8 and i16 are implicitly promoted to c_int in C, and cannot implement `VaArgSafe`.
258+ unsafe impl VaArgSafe for i32 { }
259+ unsafe impl VaArgSafe for i64 { }
260+ unsafe impl VaArgSafe for isize { }
261+
262+ // u8 and u16 are implicitly promoted to c_int in C, and cannot implement `VaArgSafe`.
263+ unsafe impl VaArgSafe for u32 { }
264+ unsafe impl VaArgSafe for u64 { }
265+ unsafe impl VaArgSafe for usize { }
266+
267+ // f32 is implicitly promoted to c_double in C, and cannot implement `VaArgSafe`.
268+ unsafe impl VaArgSafe for f64 { }
251269
252- unsafe impl < T > sealed_trait :: VaArgSafe for * mut T { }
253- unsafe impl < T > sealed_trait :: VaArgSafe for * const T { }
270+ unsafe impl < T > VaArgSafe for * mut T { }
271+ unsafe impl < T > VaArgSafe for * const T { }
254272
255273impl < ' f > VaListImpl < ' f > {
256274 /// Advance to the next arg.
257275 #[ inline]
258- pub unsafe fn arg < T : sealed_trait :: VaArgSafe > ( & mut self ) -> T {
276+ pub unsafe fn arg < T : VaArgSafe > ( & mut self ) -> T {
259277 // SAFETY: the caller must uphold the safety contract for `va_arg`.
260278 unsafe { va_arg ( self ) }
261279 }
@@ -317,4 +335,4 @@ unsafe fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>);
317335/// argument `ap` points to.
318336#[ rustc_intrinsic]
319337#[ rustc_nounwind]
320- unsafe fn va_arg < T : sealed_trait :: VaArgSafe > ( ap : & mut VaListImpl < ' _ > ) -> T ;
338+ unsafe fn va_arg < T : VaArgSafe > ( ap : & mut VaListImpl < ' _ > ) -> T ;
0 commit comments