range-diff of eeb94be..0e7395a e8e4541..a875e14 in rust-lang/rust

Legend: -  before | +  after
compiler/rustc_codegen_llvm/src/intrinsic.rs before after
    @@ compiler/rustc_codegen_llvm/src/intrinsic.rs: impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
 -                       BackendRepr::Scalar(scalar) => {
 -                           match scalar.primitive() {
 -                               Primitive::Int(..) => {
 +               }
 +               sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[], &[]),
 +               sym::va_arg => {
 +  -                match result.layout.backend_repr {
 +  -                    BackendRepr::Scalar(scalar) => {
 +  -                        match scalar.primitive() {
 +  -                            Primitive::Int(..) => {
    -                                if self.cx().size_of(result.layout.ty).bytes() < 4 {
    -                                    // `va_arg` should not be called on an integer type
    -                                    // less than 4 bytes in length. If it is, promote
    -                                } else {
    -                                    emit_va_arg(self, args[0], result.layout.ty)
    -                                }
 -  +                                // `va_arg` should not be called on an integer type
 -  +                                // less than c_int (typically i32, but i16 on avr).
 -  +                                assert!(
 -  +                                    self.cx().size_of(result.layout.ty).bits()
 -  +                                        >= u64::from(self.cx().sess().target.options.c_int_width)
 -  +                                );
 -  +                                emit_va_arg(self, args[0], result.layout.ty)
 -                               }
 -                               Primitive::Float(Float::F16) => {
 -                                   bug!("the va_arg intrinsic does not work with `f16`")
 -  @@ compiler/rustc_codegen_llvm/src/intrinsic.rs: impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
 -                               }
 -                               // `va_arg` should never be used with the return type f32.
 -                               Primitive::Float(Float::F32) => {
 +  -                            }
 +  -                            Primitive::Float(Float::F16) => {
 +  -                                bug!("the va_arg intrinsic does not work with `f16`")
 +  -                            }
 +  -                            Primitive::Float(Float::F64) | Primitive::Pointer(_) => {
 +  -                                emit_va_arg(self, args[0], result.layout.ty)
 +  -                            }
 +  -                            // `va_arg` should never be used with the return type f32.
 +  -                            Primitive::Float(Float::F32) => {
    -                                bug!("the va_arg intrinsic does not work with `f32`")
 -  +                                if self.cx().sess().target.options.c_int_width == 16 {
 -  +                                    // c_double is actually f32 on avr.
 -  +                                    emit_va_arg(self, args[0], result.layout.ty)
 -  +                                } else {
 -  +                                    bug!("the va_arg intrinsic does not work with `f32`")
 -  +                                }
 -                               }
 -                               Primitive::Float(Float::F128) => {
 -                                   bug!("the va_arg intrinsic does not work with `f128`")
 +  -                            }
 +  -                            Primitive::Float(Float::F128) => {
 +  -                                bug!("the va_arg intrinsic does not work with `f128`")
 +  -                            }
 +  +                let BackendRepr::Scalar(scalar) = result.layout.backend_repr else {
 +  +                    bug!("the va_arg intrinsic does not support non-scalar types")
 +  +                };
 +  +
 +  +                match scalar.primitive() {
 +  +                    Primitive::Pointer(_) => {
 +  +                        // Pointers are always OK.
 +  +                        emit_va_arg(self, args[0], result.layout.ty)
 +  +                    }
 +  +                    Primitive::Int(..) => {
 +  +                        let int_width = self.cx().size_of(result.layout.ty).bits();
 +  +                        let target_c_int_width = self.cx().sess().target.options.c_int_width;
 +  +                        if int_width < u64::from(target_c_int_width) {
 +  +                            // Smaller integer types are automatically promototed and `va_arg`
 +  +                            // should not be called on them.
 +  +                            bug!(
 +  +                                "va_arg got i{} but needs at least c_int (an i{})",
 +  +                                int_width,
 +  +                                target_c_int_width
 +  +                            );
 +                           }
 +  +                        emit_va_arg(self, args[0], result.layout.ty)
 +  +                    }
 +  +                    Primitive::Float(Float::F16) => {
 +  +                        bug!("the va_arg intrinsic does not support `f16`")
 +  +                    }
 +  +                    Primitive::Float(Float::F32) => {
 +  +                        if self.cx().sess().target.arch == Arch::Avr {
 +  +                            // c_double is actually f32 on avr.
 +  +                            emit_va_arg(self, args[0], result.layout.ty)
 +  +                        } else {
 +  +                            bug!("the va_arg intrinsic does not support `f32` on this target")
 +  +                        }
 +  +                    }
 +  +                    Primitive::Float(Float::F64) => {
 +  +                        // 64-bit floats are always OK.
 +  +                        emit_va_arg(self, args[0], result.layout.ty)
 +  +                    }
 +  +                    Primitive::Float(Float::F128) => {
 +  +                        bug!("the va_arg intrinsic does not support `f128`")
 +                       }
 +  -                    _ => bug!("the va_arg intrinsic does not work with non-scalar types"),
 +                   }
 +               }
 +   
compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs before after
    +                // We use implementations of VaArgSafe as the source of truth. On some embedded
    +                // targets, c_double is f32 and c_int/c_uing are i16/u16, and these types implement
    +                // VaArgSafe there. On all other targets, these types do not implement VaArgSafe.
 +  +                //
 +  +                // cfg(bootstrap): change the if let to an unwrap.
                     let arg_ty = self.structurally_resolve_type(arg.span, arg_ty);
    +                if let Some(trait_def_id) = tcx.lang_items().va_arg_safe()
    +                    && self
library/core/src/ffi/primitives.rs before after
 -  @@ library/core/src/ffi/primitives.rs: type_alias! { "c_longlong.md", c_longlong = i64; }
 -   type_alias! { "c_ulonglong.md", c_ulonglong = u64; }
 -   
 -   type_alias! { "c_float.md", c_float = f32; }
 -  -type_alias! { "c_double.md", c_double = f64; }
 -  +
 -  +crate::cfg_select! {
 -  +    any(target_arch = "avr", target_arch = "msp430") => {
 -  +        type_alias! { "c_double.md", c_double = f32; }
 -  +    }
 -  +    _ => {
 -  +        type_alias! { "c_double.md", c_double = f64; }
 -  +    }
 -  +}
 -   
 -   mod c_char_definition {
 -       crate::cfg_select! {
library/core/src/ffi/va_list.rs before after
    @@ library/core/src/ffi/va_list.rs: impl<'f> const Drop for VaList<'f> {
     mod sealed {
         pub trait Sealed {}
     
 -  +    crate::cfg_select! {
 -  +        any(target_arch = "avr", target_arch = "msp430") => {
 -  +            impl Sealed for i16 {}
 -  +            impl Sealed for u16 {}
 -  +
 -  +            impl Sealed for f32 {}
 -  +        }
 -  +        _ => {}
 -  +    }
 -  +
 +  +    impl Sealed for i16 {}
         impl Sealed for i32 {}
         impl Sealed for i64 {}
         impl Sealed for isize {}
 +   
 +  +    impl Sealed for u16 {}
 +       impl Sealed for u32 {}
 +       impl Sealed for u64 {}
 +       impl Sealed for usize {}
 +   
 +  +    impl Sealed for f32 {}
 +       impl Sealed for f64 {}
 +   
 +       impl<T> Sealed for *mut T {}
    @@ library/core/src/ffi/va_list.rs: mod sealed {
     // We may unseal this trait in the future, but currently our `va_arg` implementations don't support
     // types with an alignment larger than 8, or with a non-scalar layout. Inline assembly can be used
    -// i8 and i16 are implicitly promoted to c_int in C, and cannot implement `VaArgSafe`.
    +crate::cfg_select! {
    +    any(target_arch = "avr", target_arch = "msp430") => {
 -  +        // c_int/c_uint are i16/u16, c_double is f32 on this target.
 +  +        // c_int/c_uint are i16/u16 on these targets.
    +        //
    +        // - i8 is implicitly promoted to c_int in C, and cannot implement `VaArgSafe`.
    +        // - u8 is implicitly promoted to c_uint in C, and cannot implement `VaArgSafe`.
    +        unsafe impl VaArgSafe for i16 {}
    +        unsafe impl VaArgSafe for u16 {}
 -  +
 -  +        unsafe impl VaArgSafe for f32 {}
    +    }
    +    _ => {
 -  +        // c_int/c_uint are i32/u32, c_double is f64 on this target.
 +  +        // c_int/c_uint are i32/u32 on this target.
    +        //
    +        // - i8 and i16 are implicitly promoted to c_int in C, and cannot implement `VaArgSafe`.
    +        // - u8 and u16 are implicitly promoted to c_uint in C, and cannot implement `VaArgSafe`.
 +  +    }
 +  +}
 +  +
 +  +crate::cfg_select! {
 +  +    target_arch = "avr" => {
 +  +        // c_double is f32 on this target.
 +  +        unsafe impl VaArgSafe for f32 {}
 +  +    }
 +  +    _ => {
 +  +        // c_double is f64 on this target.
 +  +        //
    +        // - f32 is implicitly promoted to c_double in C, and cannot implement `VaArgSafe`.
    +    }
    +}
    -// f32 is implicitly promoted to c_double in C, and cannot implement `VaArgSafe`.
     unsafe impl VaArgSafe for f64 {}
     
 -   unsafe impl<T> VaArgSafe for *mut T {}
 +   unsafe impl<T> VaArgSafe for *mut T {}
 +   unsafe impl<T> VaArgSafe for *const T {}
 +   
 +  +// Check that relevant `core::ffi` types implement `VaArgSafe`.
 +  +const _: () = {
 +  +    const fn va_arg_safe_check<T: VaArgSafe>() {}
 +  +
 +  +    va_arg_safe_check::<crate::ffi::c_int>();
 +  +    va_arg_safe_check::<crate::ffi::c_uint>();
 +  +    va_arg_safe_check::<crate::ffi::c_long>();
 +  +    va_arg_safe_check::<crate::ffi::c_ulong>();
 +  +    va_arg_safe_check::<crate::ffi::c_longlong>();
 +  +    va_arg_safe_check::<crate::ffi::c_ulonglong>();
 +  +    va_arg_safe_check::<crate::ffi::c_double>();
 +  +};
 +  +
 +   impl<'f> VaList<'f> {
 +       /// Read an argument from the variable argument list, and advance to the next argument.
 +       ///
tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs before after
 -  @@ tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs:
 -   #![feature(c_variadic)]
 -   #![feature(cfg_select)]
 -   
 -  -use std::ffi::{CStr, CString, VaList, c_char, c_double, c_int, c_long, c_longlong};
 -  +use core::ffi::{CStr, VaList, c_char, c_double, c_int, c_long, c_longlong};
 -   
 -   macro_rules! continue_if {
 -       ($cond:expr) => {
 -  @@ tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs: macro_rules! continue_if {
 -       };
 -   }
 -   
 -  -unsafe fn compare_c_str(ptr: *const c_char, val: &str) -> bool {
 -  -    let cstr0 = CStr::from_ptr(ptr);
 -  -    match CString::new(val) {
 -  -        Ok(cstr1) => &*cstr1 == cstr0,
 -  -        Err(_) => false,
 -  -    }
 -  +unsafe fn compare_c_str(ptr: *const c_char, val: &CStr) -> bool {
 -  +    val == CStr::from_ptr(ptr)
 -   }
 -   
 -   #[unsafe(no_mangle)]
    @@ tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs: pub unsafe extern "C" fn check_list_1(mut ap: VaList) -> usize {
         continue_if!(ap.arg::<c_int>() == '4' as c_int);
         continue_if!(ap.arg::<c_int>() == ';' as c_int);
         continue_if!(ap.arg::<c_int>() == 0x32);
    -    continue_if!(ap.arg::<c_int>() == 0x10000001);
 -  -    continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Valid!"));
    +    continue_if!(ap.arg::<i32>() == 0x10000001);
 -  +    continue_if!(compare_c_str(ap.arg::<*const c_char>(), c"Valid!"));
 +       continue_if!(compare_c_str(ap.arg::<*const c_char>(), c"Valid!"));
         0
     }
     
     #[unsafe(no_mangle)]
     pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize {
 -  -    continue_if!(ap.arg::<c_double>().floor() == 3.14f64.floor());
 +  -    continue_if!(ap.arg::<c_double>() == 3.14f64);
    +    continue_if!(ap.arg::<c_double>() == 3.14);
         continue_if!(ap.arg::<c_long>() == 12);
         continue_if!(ap.arg::<c_int>() == 'a' as c_int);
 -  -    continue_if!(ap.arg::<c_double>().floor() == 6.18f64.floor());
 -  -    continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Hello"));
 +  -    continue_if!(ap.arg::<c_double>() == 6.28f64);
    +    continue_if!(ap.arg::<c_double>() == 6.28);
 -  +    continue_if!(compare_c_str(ap.arg::<*const c_char>(), c"Hello"));
 +       continue_if!(compare_c_str(ap.arg::<*const c_char>(), c"Hello"));
         continue_if!(ap.arg::<c_int>() == 42);
 -  -    continue_if!(compare_c_str(ap.arg::<*const c_char>(), "World"));
 -  +    continue_if!(compare_c_str(ap.arg::<*const c_char>(), c"World"));
 -       0
 -   }
 +       continue_if!(compare_c_str(ap.arg::<*const c_char>(), c"World"));
 +  @@ tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs: pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize {
     
     #[unsafe(no_mangle)]
     pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize {
 -  -    continue_if!(ap.arg::<c_double>().floor() == 6.28f64.floor());
 +  -    continue_if!(ap.arg::<c_double>() == 6.28f64);
    +    continue_if!(ap.arg::<c_double>() == 6.28);
         continue_if!(ap.arg::<c_int>() == 16);
         continue_if!(ap.arg::<c_int>() == 'A' as c_int);
 -  -    continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Skip Me!"));
 -  +    continue_if!(compare_c_str(ap.arg::<*const c_char>(), c"Skip Me!"));
 -       let mut ap = ap.clone();
 -  -    if compare_c_str(ap.arg::<*const c_char>(), "Correct") { 0 } else { 0xff }
 -  +    if compare_c_str(ap.arg::<*const c_char>(), c"Correct") { 0 } else { 0xff }
 -   }
 -   
 -   #[unsafe(no_mangle)]
 -   pub unsafe extern "C" fn check_varargs_0(_: c_int, mut ap: ...) -> usize {
 -       continue_if!(ap.arg::<c_int>() == 42);
 -  -    continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Hello, World!"));
 -  +    continue_if!(compare_c_str(ap.arg::<*const c_char>(), c"Hello, World!"));
 -       0
 -   }
 +       continue_if!(compare_c_str(ap.arg::<*const c_char>(), c"Skip Me!"));
 +  @@ tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs: pub unsafe extern "C" fn check_varargs_0(_: c_int, mut ap: ...) -> usize {
     
     #[unsafe(no_mangle)]
     pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize {
 -  -    continue_if!(ap.arg::<c_double>().floor() == 3.14f64.floor());
 +  -    continue_if!(ap.arg::<c_double>() == 3.14f64);
    +    continue_if!(ap.arg::<c_double>() == 3.14);
         continue_if!(ap.arg::<c_long>() == 12);
         continue_if!(ap.arg::<c_int>() == 'A' as c_int);
tests/run-make/c-link-to-rust-va-list-fn/rmake.rs before after
 -  @@ tests/run-make/c-link-to-rust-va-list-fn/rmake.rs:
 -   use run_make_support::{cc, extra_c_flags, run, rustc, static_lib_name};
 -   
 -   fn main() {
 -  -    rustc().input("checkrust.rs").run();
 -  +    rustc().edition("2021").input("checkrust.rs").run();
 -       cc().input("test.c")
 -           .input(static_lib_name("checkrust"))
 -           .out_exe("test")