Legend: - before | + after
Show context-only changes
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")