@@ -223,39 +223,57 @@ impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> {
223
223
}
224
224
}
225
225
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 { }
239
228
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 { }
246
241
}
247
242
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 { }
251
269
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 { }
254
272
255
273
impl < ' f > VaListImpl < ' f > {
256
274
/// Advance to the next arg.
257
275
#[ inline]
258
- pub unsafe fn arg < T : sealed_trait :: VaArgSafe > ( & mut self ) -> T {
276
+ pub unsafe fn arg < T : VaArgSafe > ( & mut self ) -> T {
259
277
// SAFETY: the caller must uphold the safety contract for `va_arg`.
260
278
unsafe { va_arg ( self ) }
261
279
}
@@ -317,4 +335,4 @@ unsafe fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>);
317
335
/// argument `ap` points to.
318
336
#[ rustc_intrinsic]
319
337
#[ 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