mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
c-variadic: handle c_int being i16 and c_double being f32 on avr
This commit is contained in:
@@ -285,37 +285,47 @@ fn codegen_intrinsic_call(
|
||||
}
|
||||
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
|
||||
// the integer to an `i32` and truncate the result
|
||||
// back to the smaller type.
|
||||
let promoted_result = emit_va_arg(self, args[0], tcx.types.i32);
|
||||
self.trunc(promoted_result, result.layout.llvm_type(self))
|
||||
} else {
|
||||
emit_va_arg(self, args[0], result.layout.ty)
|
||||
}
|
||||
}
|
||||
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`")
|
||||
}
|
||||
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")
|
||||
}
|
||||
}
|
||||
_ => bug!("the va_arg intrinsic does not work with non-scalar types"),
|
||||
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`")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -499,10 +499,16 @@ fn variadic_error<'tcx>(
|
||||
ty::Float(ty::FloatTy::F32) => {
|
||||
variadic_error(tcx.sess, arg.span, arg_ty, "c_double");
|
||||
}
|
||||
ty::Int(ty::IntTy::I8 | ty::IntTy::I16) | ty::Bool => {
|
||||
ty::Int(ty::IntTy::I8) | ty::Bool => {
|
||||
variadic_error(tcx.sess, arg.span, arg_ty, "c_int");
|
||||
}
|
||||
ty::Uint(ty::UintTy::U8 | ty::UintTy::U16) => {
|
||||
ty::Uint(ty::UintTy::U8) => {
|
||||
variadic_error(tcx.sess, arg.span, arg_ty, "c_uint");
|
||||
}
|
||||
ty::Int(ty::IntTy::I16) if tcx.sess.target.options.c_int_width > 16 => {
|
||||
variadic_error(tcx.sess, arg.span, arg_ty, "c_int");
|
||||
}
|
||||
ty::Uint(ty::UintTy::U16) if tcx.sess.target.options.c_int_width > 16 => {
|
||||
variadic_error(tcx.sess, arg.span, arg_ty, "c_uint");
|
||||
}
|
||||
ty::FnDef(..) => {
|
||||
|
||||
@@ -266,14 +266,17 @@ fn drop(&mut self) {
|
||||
mod sealed {
|
||||
pub trait Sealed {}
|
||||
|
||||
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 {}
|
||||
@@ -299,22 +302,61 @@ impl<T> Sealed for *const T {}
|
||||
// to accept unsupported types in the meantime.
|
||||
pub unsafe trait VaArgSafe: sealed::Sealed {}
|
||||
|
||||
// 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 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 {}
|
||||
}
|
||||
_ => {
|
||||
// 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`.
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl VaArgSafe for i32 {}
|
||||
unsafe impl VaArgSafe for i64 {}
|
||||
unsafe impl VaArgSafe for isize {}
|
||||
|
||||
// u8 and u16 are implicitly promoted to c_int in C, and cannot implement `VaArgSafe`.
|
||||
unsafe impl VaArgSafe for u32 {}
|
||||
unsafe impl VaArgSafe for u64 {}
|
||||
unsafe impl VaArgSafe for usize {}
|
||||
|
||||
// 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 *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.
|
||||
///
|
||||
|
||||
@@ -30,17 +30,17 @@ unsafe fn compare_c_str(ptr: *const c_char, val: &CStr) -> bool {
|
||||
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!(ap.arg::<i32>() == 0x10000001);
|
||||
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>() == 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>() == 6.28f64);
|
||||
continue_if!(ap.arg::<c_double>() == 6.28);
|
||||
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>(), c"World"));
|
||||
@@ -49,7 +49,7 @@ unsafe fn compare_c_str(ptr: *const c_char, val: &CStr) -> bool {
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize {
|
||||
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>(), c"Skip Me!"));
|
||||
@@ -66,7 +66,7 @@ unsafe fn compare_c_str(ptr: *const c_char, val: &CStr) -> bool {
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize {
|
||||
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_longlong>() == 1);
|
||||
@@ -156,7 +156,7 @@ extern "C" fn run_test_variadic() -> usize {
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
extern "C" fn run_test_va_list_by_value() -> usize {
|
||||
unsafe extern "C" fn helper(mut ap: ...) -> usize {
|
||||
unsafe extern "C" fn helper(ap: ...) -> usize {
|
||||
unsafe { test_va_list_by_value(ap) }
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ int test_rust(size_t (*fn)(va_list), ...) {
|
||||
int main(int argc, char* argv[]) {
|
||||
assert(test_rust(check_list_0, 0x01LL, 0x02, 0x03LL) == 0);
|
||||
|
||||
assert(test_rust(check_list_1, -1, 'A', '4', ';', 0x32, 0x10000001, "Valid!") == 0);
|
||||
assert(test_rust(check_list_1, -1, 'A', '4', ';', 0x32, (int32_t)0x10000001, "Valid!") == 0);
|
||||
|
||||
assert(test_rust(check_list_2, 3.14, 12l, 'a', 6.28, "Hello", 42, "World") == 0);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user