-
-
Notifications
You must be signed in to change notification settings - Fork 14.5k
support c-variadic functions in rustc_const_eval
#150601
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a7888c1
ce69380
02c4af3
ca3d1a3
f5bf335
981dacc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,8 +23,8 @@ use super::memory::MemoryKind; | |
| use super::util::ensure_monomorphic_enough; | ||
| use super::{ | ||
| AllocId, CheckInAllocMsg, ImmTy, InterpCx, InterpResult, Machine, OpTy, PlaceTy, Pointer, | ||
| PointerArithmetic, Provenance, Scalar, err_ub_custom, err_unsup_format, interp_ok, throw_inval, | ||
| throw_ub_custom, throw_ub_format, | ||
| PointerArithmetic, Projectable, Provenance, Scalar, err_ub_custom, err_unsup_format, interp_ok, | ||
| throw_inval, throw_ub, throw_ub_custom, throw_ub_format, throw_unsup_format, | ||
| }; | ||
| use crate::interpret::Writeable; | ||
|
|
||
|
|
@@ -750,6 +750,57 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { | |
| self.float_muladd_intrinsic::<Quad>(args, dest, MulAddType::Nondeterministic)? | ||
| } | ||
|
|
||
| sym::va_copy => { | ||
folkertdev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| let va_list = self.deref_pointer(&args[0])?; | ||
| let key_mplace = self.va_list_key_field(&va_list)?; | ||
| let key = self.read_pointer(&key_mplace)?; | ||
|
|
||
| let varargs = self.get_ptr_va_list(key)?; | ||
| let copy_key = self.va_list_ptr(varargs.clone()); | ||
|
|
||
| let copy_key_mplace = self.va_list_key_field(dest)?; | ||
| self.write_pointer(copy_key, ©_key_mplace)?; | ||
| } | ||
|
|
||
| sym::va_end => { | ||
| let va_list = self.deref_pointer(&args[0])?; | ||
| let key_mplace = self.va_list_key_field(&va_list)?; | ||
| let key = self.read_pointer(&key_mplace)?; | ||
|
|
||
| self.deallocate_va_list(key)?; | ||
| } | ||
|
|
||
| sym::va_arg => { | ||
| let va_list = self.deref_pointer(&args[0])?; | ||
| let key_mplace = self.va_list_key_field(&va_list)?; | ||
| let key = self.read_pointer(&key_mplace)?; | ||
|
|
||
| // Invalidate the old list and get its content. We'll recreate the | ||
| // new list (one element shorter) below. | ||
| let mut varargs = self.deallocate_va_list(key)?; | ||
folkertdev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| let Some(arg_mplace) = varargs.pop_front() else { | ||
| throw_ub!(VaArgOutOfBounds); | ||
| }; | ||
|
|
||
| // NOTE: In C some type conversions are allowed (e.g. casting between signed and | ||
| // unsigned integers). For now we require c-variadic arguments to be read with the | ||
| // exact type they were passed as. | ||
| if arg_mplace.layout.ty != dest.layout.ty { | ||
| throw_unsup_format!( | ||
| "va_arg type mismatch: requested `{}`, but next argument is `{}`", | ||
| dest.layout.ty, | ||
| arg_mplace.layout.ty | ||
| ); | ||
| } | ||
|
Comment on lines
+789
to
+795
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here we do a type comparison, would it be more idiomatic to use
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is a bit less straightforward to describe than a simple equality though.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest to open an issue about this, and keep the most strict check for now. I am not entirely certain that layout_compat is enough.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's just go with the simple rule for now then. |
||
| // Copy the argument. | ||
| self.copy_op(&arg_mplace, dest)?; | ||
|
|
||
| // Update the VaList pointer. | ||
| let new_key = self.va_list_ptr(varargs); | ||
| self.write_pointer(new_key, &key_mplace)?; | ||
| } | ||
|
|
||
| // Unsupported intrinsic: skip the return_to_block below. | ||
| _ => return interp_ok(false), | ||
| } | ||
|
|
@@ -1230,4 +1281,26 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { | |
| interp_ok(Some(ImmTy::from_scalar(val, cast_to))) | ||
| } | ||
| } | ||
|
|
||
| /// Get the MPlace of the key from the place storing the VaList. | ||
| pub(super) fn va_list_key_field<P: Projectable<'tcx, M::Provenance>>( | ||
| &self, | ||
| va_list: &P, | ||
| ) -> InterpResult<'tcx, P> { | ||
| // The struct wrapped by VaList. | ||
| let va_list_inner = self.project_field(va_list, FieldIdx::ZERO)?; | ||
|
|
||
| // Find the first pointer field in this struct. The exact index is target-specific. | ||
folkertdev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| let ty::Adt(adt, substs) = va_list_inner.layout().ty.kind() else { | ||
| bug!("invalid VaListImpl layout"); | ||
| }; | ||
|
|
||
| for (i, field) in adt.non_enum_variant().fields.iter().enumerate() { | ||
| if field.ty(*self.tcx, substs).is_raw_ptr() { | ||
| return self.project_field(&va_list_inner, FieldIdx::from_usize(i)); | ||
| } | ||
| } | ||
|
|
||
| bug!("no VaListImpl field is a pointer"); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.