Merge from rustc

This commit is contained in:
Ralf Jung
2024-12-20 11:30:04 +01:00
63 changed files with 948 additions and 610 deletions
@@ -5,7 +5,7 @@
use std::fmt;
use std::marker::PhantomData;
use rustc_index::bit_set::BitSet;
use rustc_index::bit_set::MixedBitSet;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{
self, BasicBlock, CallReturnPlaces, Local, Location, Statement, StatementKind, TerminatorEdges,
@@ -246,12 +246,14 @@ fn transfer_function(&self, state: &'a mut State) -> TransferFunction<'a, 'mir,
}
#[derive(Debug, PartialEq, Eq)]
/// The state for the `FlowSensitiveAnalysis` dataflow analysis. This domain is likely homogeneous,
/// and has a big size, so we use a bitset that can be sparse (c.f. issue #134404).
pub(super) struct State {
/// Describes whether a local contains qualif.
pub qualif: BitSet<Local>,
pub qualif: MixedBitSet<Local>,
/// Describes whether a local's address escaped and it might become qualified as a result an
/// indirect mutation.
pub borrow: BitSet<Local>,
pub borrow: MixedBitSet<Local>,
}
impl Clone for State {
@@ -320,8 +322,8 @@ impl<'tcx, Q> Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
State {
qualif: BitSet::new_empty(body.local_decls.len()),
borrow: BitSet::new_empty(body.local_decls.len()),
qualif: MixedBitSet::new_empty(body.local_decls.len()),
borrow: MixedBitSet::new_empty(body.local_decls.len()),
}
}
@@ -1,9 +1,11 @@
use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult};
use rustc_middle::mir::*;
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::{bug, span_bug, ty};
use rustc_span::def_id::DefId;
use rustc_target::callconv::FnAbi;
use crate::interpret::{
self, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic, interp_ok,
@@ -86,7 +88,7 @@ fn before_access_global(
fn find_mir_or_eval_fn(
_ecx: &mut InterpCx<'tcx, Self>,
_instance: ty::Instance<'tcx>,
_abi: rustc_abi::ExternAbi,
_abi: &FnAbi<'tcx, Ty<'tcx>>,
_args: &[interpret::FnArg<'tcx, Self::Provenance>],
_destination: &interpret::MPlaceTy<'tcx, Self::Provenance>,
_target: Option<BasicBlock>,
@@ -2,7 +2,7 @@
use std::fmt;
use std::hash::Hash;
use rustc_abi::{Align, ExternAbi, Size};
use rustc_abi::{Align, Size};
use rustc_ast::Mutability;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry};
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -14,6 +14,7 @@
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{bug, mir};
use rustc_span::{Span, Symbol, sym};
use rustc_target::callconv::FnAbi;
use tracing::debug;
use super::error::*;
@@ -339,7 +340,7 @@ fn load_mir(
fn find_mir_or_eval_fn(
ecx: &mut InterpCx<'tcx, Self>,
orig_instance: ty::Instance<'tcx>,
_abi: ExternAbi,
_abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[FnArg<'tcx>],
dest: &MPlaceTy<'tcx>,
ret: Option<mir::BasicBlock>,
@@ -519,7 +519,7 @@ pub(super) fn init_fn_call(
return M::call_extra_fn(
self,
extra,
caller_abi,
caller_fn_abi,
args,
destination,
target,
@@ -570,7 +570,7 @@ pub(super) fn init_fn_call(
let Some((body, instance)) = M::find_mir_or_eval_fn(
self,
instance,
caller_abi,
caller_fn_abi,
args,
destination,
target,
@@ -6,7 +6,7 @@
use std::fmt::Debug;
use std::hash::Hash;
use rustc_abi::{Align, ExternAbi, Size};
use rustc_abi::{Align, Size};
use rustc_apfloat::{Float, FloatConvert};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_middle::query::TyCtxtAt;
@@ -15,6 +15,7 @@
use rustc_middle::{mir, ty};
use rustc_span::Span;
use rustc_span::def_id::DefId;
use rustc_target::callconv::FnAbi;
use super::{
AllocBytes, AllocId, AllocKind, AllocRange, Allocation, CTFE_ALLOC_SALT, ConstAllocation,
@@ -201,7 +202,7 @@ fn load_mir(
fn find_mir_or_eval_fn(
ecx: &mut InterpCx<'tcx, Self>,
instance: ty::Instance<'tcx>,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[FnArg<'tcx, Self::Provenance>],
destination: &MPlaceTy<'tcx, Self::Provenance>,
target: Option<mir::BasicBlock>,
@@ -213,7 +214,7 @@ fn find_mir_or_eval_fn(
fn call_extra_fn(
ecx: &mut InterpCx<'tcx, Self>,
fn_val: Self::ExtraFnVal,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[FnArg<'tcx, Self::Provenance>],
destination: &MPlaceTy<'tcx, Self::Provenance>,
target: Option<mir::BasicBlock>,
@@ -656,7 +657,7 @@ fn check_fn_target_features(
fn call_extra_fn(
_ecx: &mut InterpCx<$tcx, Self>,
fn_val: !,
_abi: ExternAbi,
_abi: &FnAbi<$tcx, Ty<$tcx>>,
_args: &[FnArg<$tcx>],
_destination: &MPlaceTy<$tcx, Self::Provenance>,
_target: Option<mir::BasicBlock>,
+10 -17
View File
@@ -1229,23 +1229,16 @@ fn pick_all_method<'b>(
if let Some(by_value_pick) = by_value_pick {
if let Ok(by_value_pick) = by_value_pick.as_ref() {
if by_value_pick.kind == PickKind::InherentImplPick {
if let Err(e) = self.check_for_shadowed_autorefd_method(
by_value_pick,
step,
self_ty,
hir::Mutability::Not,
track_unstable_candidates,
) {
return Some(Err(e));
}
if let Err(e) = self.check_for_shadowed_autorefd_method(
by_value_pick,
step,
self_ty,
hir::Mutability::Mut,
track_unstable_candidates,
) {
return Some(Err(e));
for mutbl in [hir::Mutability::Not, hir::Mutability::Mut] {
if let Err(e) = self.check_for_shadowed_autorefd_method(
by_value_pick,
step,
self_ty,
mutbl,
track_unstable_candidates,
) {
return Some(Err(e));
}
}
}
}
+8
View File
@@ -1191,6 +1191,14 @@ pub fn iter(&self) -> MixedBitIter<'_, T> {
}
}
#[inline]
pub fn clear(&mut self) {
match self {
MixedBitSet::Small(set) => set.clear(),
MixedBitSet::Large(set) => set.clear(),
}
}
bit_relations_inherent_impls! {}
}
+6 -1
View File
@@ -1824,7 +1824,10 @@ pub fn allocator(&self) -> &A {
///
/// # Examples
///
/// This method can be useful for situations in which the vector
/// See [`spare_capacity_mut()`] for an example with safe
/// initialization of capacity elements and use of this method.
///
/// `set_len()` can be useful for situations in which the vector
/// is serving as a buffer for other code, particularly over FFI:
///
/// ```no_run
@@ -1884,6 +1887,8 @@ pub fn allocator(&self) -> &A {
///
/// Normally, here, one would use [`clear`] instead to correctly drop
/// the contents and thus not leak memory.
///
/// [`spare_capacity_mut()`]: Vec::spare_capacity_mut
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn set_len(&mut self, new_len: usize) {
+3 -3
View File
@@ -527,7 +527,7 @@ pub const fn to_bits(self) -> u32 {
/// ```
/// use std::net::Ipv4Addr;
///
/// let addr = Ipv4Addr::from(0x12345678);
/// let addr = Ipv4Addr::from_bits(0x12345678);
/// assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78), addr);
/// ```
#[rustc_const_stable(feature = "ip_bits", since = "1.80.0")]
@@ -1294,7 +1294,7 @@ pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16)
/// 0x1020, 0x3040, 0x5060, 0x7080,
/// 0x90A0, 0xB0C0, 0xD0E0, 0xF00D,
/// );
/// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr));
/// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, addr.to_bits());
/// ```
///
/// ```
@@ -1330,7 +1330,7 @@ pub const fn to_bits(self) -> u128 {
/// ```
/// use std::net::Ipv6Addr;
///
/// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128);
/// let addr = Ipv6Addr::from_bits(0x102030405060708090A0B0C0D0E0F00D_u128);
/// assert_eq!(
/// Ipv6Addr::new(
/// 0x1020, 0x3040, 0x5060, 0x7080,
+8 -7
View File
@@ -4641,7 +4641,7 @@ pub fn get_many_mut<I, const N: usize>(
/// Returns the index that an element reference points to.
///
/// Returns `None` if `element` does not point within the slice or if it points between elements.
/// Returns `None` if `element` does not point to the start of an element within the slice.
///
/// This method is useful for extending slice iterators like [`slice::split`].
///
@@ -4661,9 +4661,9 @@ pub fn get_many_mut<I, const N: usize>(
/// let num = &nums[2];
///
/// assert_eq!(num, &1);
/// assert_eq!(nums.elem_offset(num), Some(2));
/// assert_eq!(nums.element_offset(num), Some(2));
/// ```
/// Returning `None` with an in-between element:
/// Returning `None` with an unaligned element:
/// ```
/// #![feature(substr_range)]
///
@@ -4676,12 +4676,12 @@ pub fn get_many_mut<I, const N: usize>(
/// assert_eq!(ok_elm, &[0, 1]);
/// assert_eq!(weird_elm, &[1, 2]);
///
/// assert_eq!(arr.elem_offset(ok_elm), Some(0)); // Points to element 0
/// assert_eq!(arr.elem_offset(weird_elm), None); // Points between element 0 and 1
/// assert_eq!(arr.element_offset(ok_elm), Some(0)); // Points to element 0
/// assert_eq!(arr.element_offset(weird_elm), None); // Points between element 0 and 1
/// ```
#[must_use]
#[unstable(feature = "substr_range", issue = "126769")]
pub fn elem_offset(&self, element: &T) -> Option<usize> {
pub fn element_offset(&self, element: &T) -> Option<usize> {
if T::IS_ZST {
panic!("elements are zero-sized");
}
@@ -4702,7 +4702,8 @@ pub fn elem_offset(&self, element: &T) -> Option<usize> {
/// Returns the range of indices that a subslice points to.
///
/// Returns `None` if `subslice` does not point within the slice or if it points between elements.
/// Returns `None` if `subslice` does not point within the slice or if it is not aligned with the
/// elements in the slice.
///
/// This method **does not compare elements**. Instead, this method finds the location in the slice that
/// `subslice` was obtained from. To find the index of a subslice via comparison, instead use
+95 -18
View File
@@ -315,7 +315,7 @@ Markdown file, the URL given to `--markdown-playground-url` will take precedence
`--playground-url` and `#![doc(html_playground_url = "url")]` are present when rendering crate docs,
the attribute will take precedence.
### `--sort-modules-by-appearance`: control how items on module pages are sorted
## `--sort-modules-by-appearance`: control how items on module pages are sorted
Using this flag looks like this:
@@ -328,7 +328,7 @@ some consideration for their stability, and names that end in a number). Giving
`rustdoc` will disable this sorting and instead make it print the items in the order they appear in
the source.
### `--show-type-layout`: add a section to each type's docs describing its memory layout
## `--show-type-layout`: add a section to each type's docs describing its memory layout
* Tracking issue: [#113248](https://github.com/rust-lang/rust/issues/113248)
@@ -346,7 +346,7 @@ of that type will take in memory.
Note that most layout information is **completely unstable** and may even differ
between compilations.
### `--resource-suffix`: modifying the name of CSS/JavaScript in crate docs
## `--resource-suffix`: modifying the name of CSS/JavaScript in crate docs
* Tracking issue: [#54765](https://github.com/rust-lang/rust/issues/54765)
@@ -361,7 +361,7 @@ all these files are linked from every page, changing where they are can be cumbe
specially cache them. This flag will rename all these files in the output to include the suffix in
the filename. For example, `light.css` would become `light-suf.css` with the above command.
### `--extern-html-root-url`: control how rustdoc links to non-local crates
## `--extern-html-root-url`: control how rustdoc links to non-local crates
Using this flag looks like this:
@@ -376,7 +376,7 @@ flags to control that behavior. When the `--extern-html-root-url` flag is given
one of your dependencies, rustdoc use that URL for those docs. Keep in mind that if those docs exist
in the output directory, those local docs will still override this flag.
### `-Z force-unstable-if-unmarked`
## `-Z force-unstable-if-unmarked`
Using this flag looks like this:
@@ -389,7 +389,7 @@ This is an internal flag intended for the standard library and compiler that app
allows `rustdoc` to be able to generate documentation for the compiler crates and the standard
library, as an equivalent command-line argument is provided to `rustc` when building those crates.
### `--index-page`: provide a top-level landing page for docs
## `--index-page`: provide a top-level landing page for docs
This feature allows you to generate an index-page with a given markdown file. A good example of it
is the [rust documentation index](https://doc.rust-lang.org/nightly/index.html).
@@ -398,18 +398,18 @@ With this, you'll have a page which you can customize as much as you want at the
Using `index-page` option enables `enable-index-page` option as well.
### `--enable-index-page`: generate a default index page for docs
## `--enable-index-page`: generate a default index page for docs
This feature allows the generation of a default index-page which lists the generated crates.
### `--nocapture`: disable output capture for test
## `--nocapture`: disable output capture for test
When this flag is used with `--test`, the output (stdout and stderr) of your tests won't be
captured by rustdoc. Instead, the output will be directed to your terminal,
as if you had run the test executable manually. This is especially useful
for debugging your tests!
### `--check`: only checks the documentation
## `--check`: only checks the documentation
When this flag is supplied, rustdoc will type check and lint your code, but will not generate any
documentation or run your doctests.
@@ -420,7 +420,7 @@ Using this flag looks like:
rustdoc -Z unstable-options --check src/lib.rs
```
### `--static-root-path`: control how static files are loaded in HTML output
## `--static-root-path`: control how static files are loaded in HTML output
Using this flag looks like this:
@@ -435,7 +435,7 @@ JavaScript, and font files in a single location, rather than duplicating it once
files like the search index will still load from the documentation root, but anything that gets
renamed with `--resource-suffix` will load from the given path.
### `--persist-doctests`: persist doctest executables after running
## `--persist-doctests`: persist doctest executables after running
* Tracking issue: [#56925](https://github.com/rust-lang/rust/issues/56925)
@@ -449,7 +449,7 @@ This flag allows you to keep doctest executables around after they're compiled o
Usually, rustdoc will immediately discard a compiled doctest after it's been tested, but
with this option, you can keep those binaries around for farther testing.
### `--show-coverage`: calculate the percentage of items with documentation
## `--show-coverage`: calculate the percentage of items with documentation
* Tracking issue: [#58154](https://github.com/rust-lang/rust/issues/58154)
@@ -500,7 +500,7 @@ Calculating code examples follows these rules:
* typedef
2. If one of the previously listed items has a code example, then it'll be counted.
#### JSON output
### JSON output
When using `--output-format json` with this option, it will display the coverage information in
JSON format. For example, here is the JSON for a file with one documented item and one
@@ -522,7 +522,7 @@ Note that the third item is the crate root, which in this case is undocumented.
If you want the JSON output to be displayed on `stdout` instead of having a file generated, you can
use `-o -`.
### `-w`/`--output-format`: output format
## `-w`/`--output-format`: output format
`--output-format json` emits documentation in the experimental
[JSON format](https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc_json_types/). `--output-format html` has no effect,
@@ -542,7 +542,7 @@ It can also be used with `--show-coverage`. Take a look at its
[documentation](#--show-coverage-calculate-the-percentage-of-items-with-documentation) for more
information.
### `--enable-per-target-ignores`: allow `ignore-foo` style filters for doctests
## `--enable-per-target-ignores`: allow `ignore-foo` style filters for doctests
* Tracking issue: [#64245](https://github.com/rust-lang/rust/issues/64245)
@@ -577,7 +577,7 @@ struct Foo;
In older versions, this will be ignored on all targets, but on newer versions `ignore-gnu` will
override `ignore`.
### `--runtool`, `--runtool-arg`: program to run tests with; args to pass to it
## `--runtool`, `--runtool-arg`: program to run tests with; args to pass to it
* Tracking issue: [#64245](https://github.com/rust-lang/rust/issues/64245)
@@ -596,7 +596,7 @@ $ rustdoc src/lib.rs -Z unstable-options --runtool valgrind
Another use case would be to run a test inside an emulator, or through a Virtual Machine.
### `--with-examples`: include examples of uses of items as documentation
## `--with-examples`: include examples of uses of items as documentation
* Tracking issue: [#88791](https://github.com/rust-lang/rust/issues/88791)
@@ -625,7 +625,7 @@ crate being documented (`foobar`) and a path to output the calls
To scrape examples from test code, e.g. functions marked `#[test]`, then
add the `--scrape-tests` flag.
### `--generate-link-to-definition`: Generate links on types in source code
## `--generate-link-to-definition`: Generate links on types in source code
* Tracking issue: [#89095](https://github.com/rust-lang/rust/issues/89095)
@@ -664,3 +664,80 @@ Similar to cargo `build.rustc-wrapper` option, this flag takes a `rustc` wrapper
The first argument to the program will be the test builder program.
This flag can be passed multiple times to nest wrappers.
## Passing arguments to rustc when compiling doctests
You can use the `--doctest-compilation-args` flag if you want to add options when compiling the
doctest. For example if you have:
```rust,no_run
/// ```
/// #![deny(warnings)]
/// #![feature(async_await)]
///
/// let x = 12;
/// ```
pub struct Bar;
```
And you run `rustdoc --test` on it, you will get:
```console
running 1 test
test foo.rs - Bar (line 1) ... FAILED
failures:
---- foo.rs - Bar (line 1) stdout ----
error: the feature `async_await` has been stable since 1.39.0 and no longer requires an attribute to enable
--> foo.rs:2:12
|
3 | #![feature(async_await)]
| ^^^^^^^^^^^
|
note: the lint level is defined here
--> foo.rs:1:9
|
2 | #![deny(warnings)]
| ^^^^^^^^
= note: `#[deny(stable_features)]` implied by `#[deny(warnings)]`
error: aborting due to 1 previous error
Couldn't compile the test.
failures:
foo.rs - Bar (line 1)
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s
```
But if you can limit the lint level to warning by using `--doctest_compilation_args=--cap-lints=warn`:
```console
$ rustdoc --test --doctest_compilation_args=--cap-lints=warn file.rs
running 1 test
test tests/rustdoc-ui/doctest/rustflags.rs - Bar (line 5) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s
```
The parsing of arguments works as follows: if it encounters a `"` or a `'`, it will continue
until it finds the character unescaped (without a prepending `\`). If not inside a string, a
whitespace character will also split arguments. Example:
```text
"hello 'a'\" ok" how are 'you today?'
```
will be split as follows:
```text
[
"hello 'a'\" ok",
"how",
"are",
"you today?",
]
```
+27 -20
View File
@@ -1222,14 +1222,16 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
let local_did = trait_item.owner_id.to_def_id();
cx.with_param_env(local_did, |cx| {
let inner = match trait_item.kind {
hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(Box::new(Constant {
generics: enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)),
kind: ConstantKind::Local { def_id: local_did, body: default },
type_: clean_ty(ty, cx),
})),
hir::TraitItemKind::Const(ty, Some(default)) => {
ProvidedAssocConstItem(Box::new(Constant {
generics: enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)),
kind: ConstantKind::Local { def_id: local_did, body: default },
type_: clean_ty(ty, cx),
}))
}
hir::TraitItemKind::Const(ty, None) => {
let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
TyAssocConstItem(generics, Box::new(clean_ty(ty, cx)))
RequiredAssocConstItem(generics, Box::new(clean_ty(ty, cx)))
}
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Body(body));
@@ -1237,7 +1239,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
}
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Names(names));
TyMethodItem(m)
RequiredMethodItem(m)
}
hir::TraitItemKind::Type(bounds, Some(default)) => {
let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
@@ -1257,7 +1259,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
hir::TraitItemKind::Type(bounds, None) => {
let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
TyAssocTypeItem(generics, bounds)
RequiredAssocTypeItem(generics, bounds)
}
};
Item::from_def_id_and_parts(local_did, Some(trait_item.ident.name), inner, cx)
@@ -1271,7 +1273,7 @@ pub(crate) fn clean_impl_item<'tcx>(
let local_did = impl_.owner_id.to_def_id();
cx.with_param_env(local_did, |cx| {
let inner = match impl_.kind {
hir::ImplItemKind::Const(ty, expr) => AssocConstItem(Box::new(Constant {
hir::ImplItemKind::Const(ty, expr) => ImplAssocConstItem(Box::new(Constant {
generics: clean_generics(impl_.generics, cx),
kind: ConstantKind::Local { def_id: local_did, body: expr },
type_: clean_ty(ty, cx),
@@ -1320,18 +1322,23 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
);
simplify::move_bounds_to_generic_parameters(&mut generics);
let provided = match assoc_item.container {
ty::AssocItemContainer::Impl => true,
ty::AssocItemContainer::Trait => tcx.defaultness(assoc_item.def_id).has_value(),
};
if provided {
AssocConstItem(Box::new(Constant {
match assoc_item.container {
ty::AssocItemContainer::Impl => ImplAssocConstItem(Box::new(Constant {
generics,
kind: ConstantKind::Extern { def_id: assoc_item.def_id },
type_: ty,
}))
} else {
TyAssocConstItem(generics, Box::new(ty))
})),
ty::AssocItemContainer::Trait => {
if tcx.defaultness(assoc_item.def_id).has_value() {
ProvidedAssocConstItem(Box::new(Constant {
generics,
kind: ConstantKind::Extern { def_id: assoc_item.def_id },
type_: ty,
}))
} else {
RequiredAssocConstItem(generics, Box::new(ty))
}
}
}
}
ty::AssocKind::Fn => {
@@ -1369,7 +1376,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
};
MethodItem(item, defaultness)
} else {
TyMethodItem(item)
RequiredMethodItem(item)
}
}
ty::AssocKind::Type => {
@@ -1486,7 +1493,7 @@ fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
bounds,
)
} else {
TyAssocTypeItem(generics, bounds)
RequiredAssocTypeItem(generics, bounds)
}
} else {
AssocTypeItem(
+28 -18
View File
@@ -545,14 +545,14 @@ pub(crate) fn is_variant(&self) -> bool {
pub(crate) fn is_associated_type(&self) -> bool {
matches!(self.kind, AssocTypeItem(..) | StrippedItem(box AssocTypeItem(..)))
}
pub(crate) fn is_ty_associated_type(&self) -> bool {
matches!(self.kind, TyAssocTypeItem(..) | StrippedItem(box TyAssocTypeItem(..)))
pub(crate) fn is_required_associated_type(&self) -> bool {
matches!(self.kind, RequiredAssocTypeItem(..) | StrippedItem(box RequiredAssocTypeItem(..)))
}
pub(crate) fn is_associated_const(&self) -> bool {
matches!(self.kind, AssocConstItem(..) | StrippedItem(box AssocConstItem(..)))
matches!(self.kind, ProvidedAssocConstItem(..) | ImplAssocConstItem(..) | StrippedItem(box (ProvidedAssocConstItem(..) | ImplAssocConstItem(..))))
}
pub(crate) fn is_ty_associated_const(&self) -> bool {
matches!(self.kind, TyAssocConstItem(..) | StrippedItem(box TyAssocConstItem(..)))
pub(crate) fn is_required_associated_const(&self) -> bool {
matches!(self.kind, RequiredAssocConstItem(..) | StrippedItem(box RequiredAssocConstItem(..)))
}
pub(crate) fn is_method(&self) -> bool {
self.type_() == ItemType::Method
@@ -669,7 +669,9 @@ fn build_fn_header(
asyncness: hir::IsAsync::NotAsync,
}
}
ItemKind::FunctionItem(_) | ItemKind::MethodItem(_, _) | ItemKind::TyMethodItem(_) => {
ItemKind::FunctionItem(_)
| ItemKind::MethodItem(_, _)
| ItemKind::RequiredMethodItem(_) => {
let def_id = self.def_id().unwrap();
build_fn_header(def_id, tcx, tcx.asyncness(def_id))
}
@@ -699,8 +701,13 @@ pub(crate) fn visibility(&self, tcx: TyCtxt<'_>) -> Option<Visibility<DefId>> {
// Variants always inherit visibility
VariantItem(..) | ImplItem(..) => return None,
// Trait items inherit the trait's visibility
AssocConstItem(..) | TyAssocConstItem(..) | AssocTypeItem(..) | TyAssocTypeItem(..)
| TyMethodItem(..) | MethodItem(..) => {
RequiredAssocConstItem(..)
| ProvidedAssocConstItem(..)
| ImplAssocConstItem(..)
| AssocTypeItem(..)
| RequiredAssocTypeItem(..)
| RequiredMethodItem(..)
| MethodItem(..) => {
let assoc_item = tcx.associated_item(def_id);
let is_trait_item = match assoc_item.container {
ty::AssocItemContainer::Trait => true,
@@ -845,10 +852,10 @@ pub(crate) enum ItemKind {
TraitAliasItem(TraitAlias),
ImplItem(Box<Impl>),
/// A required method in a trait declaration meaning it's only a function signature.
TyMethodItem(Box<Function>),
RequiredMethodItem(Box<Function>),
/// A method in a trait impl or a provided method in a trait declaration.
///
/// Compared to [TyMethodItem], it also contains a method body.
/// Compared to [RequiredMethodItem], it also contains a method body.
MethodItem(Box<Function>, Option<hir::Defaultness>),
StructFieldItem(Type),
VariantItem(Variant),
@@ -862,14 +869,16 @@ pub(crate) enum ItemKind {
ProcMacroItem(ProcMacro),
PrimitiveItem(PrimitiveType),
/// A required associated constant in a trait declaration.
TyAssocConstItem(Generics, Box<Type>),
RequiredAssocConstItem(Generics, Box<Type>),
ConstantItem(Box<Constant>),
/// An associated constant in a trait impl or a provided one in a trait declaration.
AssocConstItem(Box<Constant>),
/// An associated constant in a trait declaration with provided default value.
ProvidedAssocConstItem(Box<Constant>),
/// An associated constant in an inherent impl or trait impl.
ImplAssocConstItem(Box<Constant>),
/// A required associated type in a trait declaration.
///
/// The bounds may be non-empty if there is a `where` clause.
TyAssocTypeItem(Generics, Vec<GenericBound>),
RequiredAssocTypeItem(Generics, Vec<GenericBound>),
/// An associated type in a trait impl or a provided one in a trait declaration.
AssocTypeItem(Box<TypeAlias>, Vec<GenericBound>),
/// An item that has been stripped by a rustdoc pass
@@ -900,7 +909,7 @@ pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
| StaticItem(_)
| ConstantItem(_)
| TraitAliasItem(_)
| TyMethodItem(_)
| RequiredMethodItem(_)
| MethodItem(_, _)
| StructFieldItem(_)
| ForeignFunctionItem(_, _)
@@ -909,9 +918,10 @@ pub(crate) fn inner_items(&self) -> impl Iterator<Item = &Item> {
| MacroItem(_)
| ProcMacroItem(_)
| PrimitiveItem(_)
| TyAssocConstItem(..)
| AssocConstItem(..)
| TyAssocTypeItem(..)
| RequiredAssocConstItem(..)
| ProvidedAssocConstItem(..)
| ImplAssocConstItem(..)
| RequiredAssocTypeItem(..)
| AssocTypeItem(..)
| StrippedItem(_)
| KeywordItem => [].iter(),
+5
View File
@@ -172,6 +172,9 @@ pub(crate) struct Options {
/// This is mainly useful for other tools that reads that debuginfo to figure out
/// how to call the compiler with the same arguments.
pub(crate) expanded_args: Vec<String>,
/// Arguments to be used when compiling doctests.
pub(crate) doctest_compilation_args: Vec<String>,
}
impl fmt::Debug for Options {
@@ -774,6 +777,7 @@ fn println_condition(condition: Condition) {
let scrape_examples_options = ScrapeExamplesOptions::new(matches, dcx);
let with_examples = matches.opt_strs("with-examples");
let call_locations = crate::scrape_examples::load_call_locations(with_examples, dcx);
let doctest_compilation_args = matches.opt_strs("doctest-compilation-args");
let unstable_features =
rustc_feature::UnstableFeatures::from_environment(crate_name.as_deref());
@@ -819,6 +823,7 @@ fn println_condition(condition: Condition) {
scrape_examples_options,
unstable_features,
expanded_args: args,
doctest_compilation_args,
};
let render_options = RenderOptions {
output,
+44
View File
@@ -50,6 +50,46 @@ pub(crate) struct GlobalTestOptions {
pub(crate) args_file: PathBuf,
}
/// Function used to split command line arguments just like a shell would.
fn split_args(args: &str) -> Vec<String> {
let mut out = Vec::new();
let mut iter = args.chars();
let mut current = String::new();
while let Some(c) = iter.next() {
if c == '\\' {
if let Some(c) = iter.next() {
// If it's escaped, even a quote or a whitespace will be ignored.
current.push(c);
}
} else if c == '"' || c == '\'' {
while let Some(new_c) = iter.next() {
if new_c == c {
break;
} else if new_c == '\\' {
if let Some(c) = iter.next() {
// If it's escaped, even a quote will be ignored.
current.push(c);
}
} else {
current.push(new_c);
}
}
} else if " \n\t\r".contains(c) {
if !current.is_empty() {
out.push(current.clone());
current.clear();
}
} else {
current.push(c);
}
}
if !current.is_empty() {
out.push(current);
}
out
}
pub(crate) fn generate_args_file(file_path: &Path, options: &RustdocOptions) -> Result<(), String> {
let mut file = File::create(file_path)
.map_err(|error| format!("failed to create args file: {error:?}"))?;
@@ -78,6 +118,10 @@ pub(crate) fn generate_args_file(file_path: &Path, options: &RustdocOptions) ->
content.push(format!("-Z{unstable_option_str}"));
}
for compilation_args in &options.doctest_compilation_args {
content.extend(split_args(compilation_args));
}
let content = content.join("\n");
file.write_all(content.as_bytes())
+22
View File
@@ -379,3 +379,25 @@ fn main() {
let (output, len) = make_test(input, None, false, &opts, None);
assert_eq!((output, len), (expected, 1));
}
#[test]
fn check_split_args() {
fn compare(input: &str, expected: &[&str]) {
let output = super::split_args(input);
let expected = expected.iter().map(|s| s.to_string()).collect::<Vec<_>>();
assert_eq!(expected, output, "test failed for {input:?}");
}
compare("'a' \"b\"c", &["a", "bc"]);
compare("'a' \"b \"c d", &["a", "b c", "d"]);
compare("'a' \"b\\\"c\"", &["a", "b\"c"]);
compare("'a\"'", &["a\""]);
compare("\"a'\"", &["a'"]);
compare("\\ a", &[" a"]);
compare("\\\\", &["\\"]);
compare("a'", &["a"]);
compare("a ", &["a"]);
compare("a b", &["a", "b"]);
compare("a\n\t \rb", &["a", "b"]);
compare("a\n\t1 \rb", &["a", "1", "b"]);
}
+5 -4
View File
@@ -82,7 +82,7 @@ fn fold_inner_recur(&mut self, kind: ItemKind) -> ItemKind {
| StaticItem(_)
| ConstantItem(..)
| TraitAliasItem(_)
| TyMethodItem(_)
| RequiredMethodItem(_)
| MethodItem(_, _)
| StructFieldItem(_)
| ForeignFunctionItem(..)
@@ -91,9 +91,10 @@ fn fold_inner_recur(&mut self, kind: ItemKind) -> ItemKind {
| MacroItem(_)
| ProcMacroItem(_)
| PrimitiveItem(_)
| TyAssocConstItem(..)
| AssocConstItem(..)
| TyAssocTypeItem(..)
| RequiredAssocConstItem(..)
| ProvidedAssocConstItem(..)
| ImplAssocConstItem(..)
| RequiredAssocTypeItem(..)
| AssocTypeItem(..)
| KeywordItem => kind,
}
+15 -9
View File
@@ -334,12 +334,13 @@ fn is_from_private_dep(tcx: TyCtxt<'_>, cache: &Cache, def_id: DefId) -> bool {
clean::ExternCrateItem { .. }
| clean::ImportItem(..)
| clean::ImplItem(..)
| clean::TyMethodItem(..)
| clean::RequiredMethodItem(..)
| clean::MethodItem(..)
| clean::StructFieldItem(..)
| clean::TyAssocConstItem(..)
| clean::AssocConstItem(..)
| clean::TyAssocTypeItem(..)
| clean::RequiredAssocConstItem(..)
| clean::ProvidedAssocConstItem(..)
| clean::ImplAssocConstItem(..)
| clean::RequiredAssocTypeItem(..)
| clean::AssocTypeItem(..)
| clean::StrippedItem(..)
| clean::KeywordItem => {
@@ -443,15 +444,17 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It
let item_def_id = item.item_id.as_def_id().unwrap();
let (parent_did, parent_path) = match item.kind {
clean::StrippedItem(..) => return,
clean::AssocConstItem(..) | clean::AssocTypeItem(..)
clean::ProvidedAssocConstItem(..)
| clean::ImplAssocConstItem(..)
| clean::AssocTypeItem(..)
if cache.parent_stack.last().is_some_and(|parent| parent.is_trait_impl()) =>
{
// skip associated items in trait impls
return;
}
clean::TyMethodItem(..)
| clean::TyAssocConstItem(..)
| clean::TyAssocTypeItem(..)
clean::RequiredMethodItem(..)
| clean::RequiredAssocConstItem(..)
| clean::RequiredAssocTypeItem(..)
| clean::StructFieldItem(..)
| clean::VariantItem(..) => {
// Don't index if containing module is stripped (i.e., private),
@@ -467,7 +470,10 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It
let parent_path = &cache.stack[..cache.stack.len() - 1];
(Some(parent_did), parent_path)
}
clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => {
clean::MethodItem(..)
| clean::ProvidedAssocConstItem(..)
| clean::ImplAssocConstItem(..)
| clean::AssocTypeItem(..) => {
let last = cache.parent_stack.last().expect("parent_stack is empty 2");
let parent_did = match last {
// impl Trait for &T { fn method(self); }
+5 -3
View File
@@ -88,7 +88,7 @@ fn from(item: &'a clean::Item) -> ItemType {
clean::ConstantItem(..) => ItemType::Constant,
clean::TraitItem(..) => ItemType::Trait,
clean::ImplItem(..) => ItemType::Impl,
clean::TyMethodItem(..) => ItemType::TyMethod,
clean::RequiredMethodItem(..) => ItemType::TyMethod,
clean::MethodItem(..) => ItemType::Method,
clean::StructFieldItem(..) => ItemType::StructField,
clean::VariantItem(..) => ItemType::Variant,
@@ -96,8 +96,10 @@ fn from(item: &'a clean::Item) -> ItemType {
clean::ForeignStaticItem(..) => ItemType::Static, // no ForeignStatic
clean::MacroItem(..) => ItemType::Macro,
clean::PrimitiveItem(..) => ItemType::Primitive,
clean::TyAssocConstItem(..) | clean::AssocConstItem(..) => ItemType::AssocConst,
clean::TyAssocTypeItem(..) | clean::AssocTypeItem(..) => ItemType::AssocType,
clean::RequiredAssocConstItem(..)
| clean::ProvidedAssocConstItem(..)
| clean::ImplAssocConstItem(..) => ItemType::AssocConst,
clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => ItemType::AssocType,
clean::ForeignTypeItem => ItemType::ForeignType,
clean::KeywordItem => ItemType::Keyword,
clean::TraitAliasItem(..) => ItemType::TraitAlias,
+53 -21
View File
@@ -836,12 +836,23 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
href.map(|href| format!(" href=\"{href}\"")).unwrap_or_default()
}
#[derive(Debug)]
enum AssocConstValue<'a> {
// In trait definitions, it is relevant for the public API whether an
// associated constant comes with a default value, so even if we cannot
// render its value, the presence of a value must be shown using `= _`.
TraitDefault(&'a clean::ConstantKind),
// In impls, there is no need to show `= _`.
Impl(&'a clean::ConstantKind),
None,
}
fn assoc_const(
w: &mut Buffer,
it: &clean::Item,
generics: &clean::Generics,
ty: &clean::Type,
default: Option<&clean::ConstantKind>,
value: AssocConstValue<'_>,
link: AssocItemLink<'_>,
indent: usize,
cx: &Context<'_>,
@@ -857,15 +868,20 @@ fn assoc_const(
generics = generics.print(cx),
ty = ty.print(cx),
);
if let Some(default) = default {
w.write_str(" = ");
if let AssocConstValue::TraitDefault(konst) | AssocConstValue::Impl(konst) = value {
// FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the
// hood which adds noisy underscores and a type suffix to number literals.
// This hurts readability in this context especially when more complex expressions
// are involved and it doesn't add much of value.
// Find a way to print constants here without all that jazz.
write!(w, "{}", Escape(&default.value(tcx).unwrap_or_else(|| default.expr(tcx))));
let repr = konst.value(tcx).unwrap_or_else(|| konst.expr(tcx));
if match value {
AssocConstValue::TraitDefault(_) => true, // always show
AssocConstValue::Impl(_) => repr != "_", // show if there is a meaningful value to show
AssocConstValue::None => unreachable!(),
} {
write!(w, " = {}", Escape(&repr));
}
}
write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
}
@@ -1076,33 +1092,43 @@ fn render_assoc_item(
) {
match &item.kind {
clean::StrippedItem(..) => {}
clean::TyMethodItem(m) => {
clean::RequiredMethodItem(m) => {
assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode)
}
clean::MethodItem(m, _) => {
assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode)
}
clean::TyAssocConstItem(generics, ty) => assoc_const(
clean::RequiredAssocConstItem(generics, ty) => assoc_const(
w,
item,
generics,
ty,
None,
AssocConstValue::None,
link,
if parent == ItemType::Trait { 4 } else { 0 },
cx,
),
clean::AssocConstItem(ci) => assoc_const(
clean::ProvidedAssocConstItem(ci) => assoc_const(
w,
item,
&ci.generics,
&ci.type_,
Some(&ci.kind),
AssocConstValue::TraitDefault(&ci.kind),
link,
if parent == ItemType::Trait { 4 } else { 0 },
cx,
),
clean::TyAssocTypeItem(ref generics, ref bounds) => assoc_type(
clean::ImplAssocConstItem(ci) => assoc_const(
w,
item,
&ci.generics,
&ci.type_,
AssocConstValue::Impl(&ci.kind),
link,
if parent == ItemType::Trait { 4 } else { 0 },
cx,
),
clean::RequiredAssocTypeItem(ref generics, ref bounds) => assoc_type(
w,
item,
generics,
@@ -1384,7 +1410,7 @@ fn render_deref_methods(
fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
let self_type_opt = match item.kind {
clean::MethodItem(ref method, _) => method.decl.receiver_type(),
clean::TyMethodItem(ref method) => method.decl.receiver_type(),
clean::RequiredMethodItem(ref method) => method.decl.receiver_type(),
_ => None,
};
@@ -1660,7 +1686,7 @@ fn doc_impl_item(
write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>");
}
match &item.kind {
clean::MethodItem(..) | clean::TyMethodItem(_) => {
clean::MethodItem(..) | clean::RequiredMethodItem(_) => {
// Only render when the method is not static or we allow static methods
if render_method_item {
let id = cx.derive_id(format!("{item_type}.{name}"));
@@ -1690,7 +1716,7 @@ fn doc_impl_item(
w.write_str("</h4></section>");
}
}
clean::TyAssocConstItem(ref generics, ref ty) => {
clean::RequiredAssocConstItem(ref generics, ref ty) => {
let source_id = format!("{item_type}.{name}");
let id = cx.derive_id(&source_id);
write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
@@ -1705,14 +1731,14 @@ fn doc_impl_item(
item,
generics,
ty,
None,
AssocConstValue::None,
link.anchor(if trait_.is_some() { &source_id } else { &id }),
0,
cx,
);
w.write_str("</h4></section>");
}
clean::AssocConstItem(ci) => {
clean::ProvidedAssocConstItem(ci) | clean::ImplAssocConstItem(ci) => {
let source_id = format!("{item_type}.{name}");
let id = cx.derive_id(&source_id);
write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
@@ -1727,14 +1753,18 @@ fn doc_impl_item(
item,
&ci.generics,
&ci.type_,
Some(&ci.kind),
match item.kind {
clean::ProvidedAssocConstItem(_) => AssocConstValue::TraitDefault(&ci.kind),
clean::ImplAssocConstItem(_) => AssocConstValue::Impl(&ci.kind),
_ => unreachable!(),
},
link.anchor(if trait_.is_some() { &source_id } else { &id }),
0,
cx,
);
w.write_str("</h4></section>");
}
clean::TyAssocTypeItem(ref generics, ref bounds) => {
clean::RequiredAssocTypeItem(ref generics, ref bounds) => {
let source_id = format!("{item_type}.{name}");
let id = cx.derive_id(&source_id);
write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
@@ -1809,11 +1839,13 @@ fn doc_impl_item(
if !impl_.is_negative_trait_impl() {
for trait_item in &impl_.items {
match trait_item.kind {
clean::MethodItem(..) | clean::TyMethodItem(_) => methods.push(trait_item),
clean::TyAssocTypeItem(..) | clean::AssocTypeItem(..) => {
clean::MethodItem(..) | clean::RequiredMethodItem(_) => methods.push(trait_item),
clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => {
assoc_types.push(trait_item)
}
clean::TyAssocConstItem(..) | clean::AssocConstItem(_) => {
clean::RequiredAssocConstItem(..)
| clean::ProvidedAssocConstItem(_)
| clean::ImplAssocConstItem(_) => {
// We render it directly since they're supposed to come first.
doc_impl_item(
&mut default_impl_items,
+4 -2
View File
@@ -651,9 +651,11 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) {
let tcx = cx.tcx();
let bounds = bounds(&t.bounds, false, cx);
let required_types = t.items.iter().filter(|m| m.is_ty_associated_type()).collect::<Vec<_>>();
let required_types =
t.items.iter().filter(|m| m.is_required_associated_type()).collect::<Vec<_>>();
let provided_types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>();
let required_consts = t.items.iter().filter(|m| m.is_ty_associated_const()).collect::<Vec<_>>();
let required_consts =
t.items.iter().filter(|m| m.is_required_associated_const()).collect::<Vec<_>>();
let provided_consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>();
let required_methods = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>();
let provided_methods = t.items.iter().filter(|m| m.is_method()).collect::<Vec<_>>();
+4 -3
View File
@@ -837,7 +837,7 @@ pub(crate) fn get_function_type_for_search(
clean::ForeignFunctionItem(ref f, _)
| clean::FunctionItem(ref f)
| clean::MethodItem(ref f, _)
| clean::TyMethodItem(ref f) => {
| clean::RequiredMethodItem(ref f) => {
get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache)
}
_ => return None,
@@ -1207,10 +1207,11 @@ fn simplify_fn_type<'a, 'tcx>(
&& let Type::Path { path } = arg
&& let def_id = path.def_id()
&& let Some(trait_) = cache.traits.get(&def_id)
&& trait_.items.iter().any(|at| at.is_ty_associated_type())
&& trait_.items.iter().any(|at| at.is_required_associated_type())
{
for assoc_ty in &trait_.items {
if let clean::ItemKind::TyAssocTypeItem(_generics, bounds) = &assoc_ty.kind
if let clean::ItemKind::RequiredAssocTypeItem(_generics, bounds) =
&assoc_ty.kind
&& let Some(name) = assoc_ty.name
{
let idx = -isize::try_from(rgen.len() + 1).unwrap();
+2 -2
View File
@@ -282,10 +282,10 @@ fn filter_items<'a>(
res
}
let req_assoc = filter_items(&t.items, |m| m.is_ty_associated_type(), "associatedtype");
let req_assoc = filter_items(&t.items, |m| m.is_required_associated_type(), "associatedtype");
let prov_assoc = filter_items(&t.items, |m| m.is_associated_type(), "associatedtype");
let req_assoc_const =
filter_items(&t.items, |m| m.is_ty_associated_const(), "associatedconstant");
filter_items(&t.items, |m| m.is_required_associated_const(), "associatedconstant");
let prov_assoc_const =
filter_items(&t.items, |m| m.is_associated_const(), "associatedconstant");
let req_method = filter_items(&t.items, |m| m.is_ty_method(), "tymethod");
+6 -4
View File
@@ -319,7 +319,9 @@ fn from_clean_item(item: clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum {
TraitItem(t) => ItemEnum::Trait((*t).into_json(renderer)),
TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_json(renderer)),
MethodItem(m, _) => ItemEnum::Function(from_function(m, true, header.unwrap(), renderer)),
TyMethodItem(m) => ItemEnum::Function(from_function(m, false, header.unwrap(), renderer)),
RequiredMethodItem(m) => {
ItemEnum::Function(from_function(m, false, header.unwrap(), renderer))
}
ImplItem(i) => ItemEnum::Impl((*i).into_json(renderer)),
StaticItem(s) => ItemEnum::Static(convert_static(s, rustc_hir::Safety::Safe, renderer)),
ForeignStaticItem(s, safety) => ItemEnum::Static(convert_static(s, safety, renderer)),
@@ -339,15 +341,15 @@ fn from_clean_item(item: clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum {
})
}
// FIXME(generic_const_items): Add support for generic associated consts.
TyAssocConstItem(_generics, ty) => {
RequiredAssocConstItem(_generics, ty) => {
ItemEnum::AssocConst { type_: (*ty).into_json(renderer), value: None }
}
// FIXME(generic_const_items): Add support for generic associated consts.
AssocConstItem(ci) => ItemEnum::AssocConst {
ProvidedAssocConstItem(ci) | ImplAssocConstItem(ci) => ItemEnum::AssocConst {
type_: ci.type_.into_json(renderer),
value: Some(ci.kind.expr(renderer.tcx)),
},
TyAssocTypeItem(g, b) => ItemEnum::AssocType {
RequiredAssocTypeItem(g, b) => ItemEnum::AssocType {
generics: g.into_json(renderer),
bounds: b.into_json(renderer),
type_: None,
+9 -1
View File
@@ -642,6 +642,15 @@ fn opts() -> Vec<RustcOptGroup> {
"Includes trait implementations and other crate info from provided path. Only use with --merge=finalize",
"path/to/doc.parts/<crate-name>",
),
opt(Unstable, Flag, "", "html-no-source", "Disable HTML source code pages generation", ""),
opt(
Unstable,
Multi,
"",
"doctest-compilation-args",
"",
"add arguments to be used when compiling doctests",
),
// deprecated / removed options
opt(Unstable, FlagMulti, "", "disable-minification", "removed", ""),
opt(
@@ -684,7 +693,6 @@ fn opts() -> Vec<RustcOptGroup> {
"removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information",
"[rust]",
),
opt(Unstable, Flag, "", "html-no-source", "Disable HTML source code pages generation", ""),
]
}
@@ -72,10 +72,11 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -
| clean::ForeignFunctionItem(..)
| clean::ForeignStaticItem(..)
| clean::ForeignTypeItem
| clean::AssocConstItem(..)
| clean::AssocTypeItem(..)
| clean::TyAssocConstItem(..)
| clean::TyAssocTypeItem(..)
| clean::RequiredAssocConstItem(..)
| clean::ProvidedAssocConstItem(..)
| clean::ImplAssocConstItem(..)
| clean::RequiredAssocTypeItem(..)
// check for trait impl
| clean::ImplItem(box clean::Impl { trait_: Some(_), .. })
)
+5 -4
View File
@@ -67,11 +67,12 @@ fn fold_item(&mut self, mut item: Item) -> Option<Item> {
// Don't inherit the parent's stability for these items, because they
// are potentially accessible even if the parent is more unstable.
ItemKind::ImplItem(..)
| ItemKind::TyMethodItem(..)
| ItemKind::RequiredMethodItem(..)
| ItemKind::MethodItem(..)
| ItemKind::TyAssocConstItem(..)
| ItemKind::AssocConstItem(..)
| ItemKind::TyAssocTypeItem(..)
| ItemKind::RequiredAssocConstItem(..)
| ItemKind::ProvidedAssocConstItem(..)
| ItemKind::ImplAssocConstItem(..)
| ItemKind::RequiredAssocTypeItem(..)
| ItemKind::AssocTypeItem(..)
| ItemKind::PrimitiveItem(..)
| ItemKind::KeywordItem => own_stability,
+7 -2
View File
@@ -79,7 +79,10 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
}
}
clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => {
clean::MethodItem(..)
| clean::ProvidedAssocConstItem(..)
| clean::ImplAssocConstItem(..)
| clean::AssocTypeItem(..) => {
let item_id = i.item_id;
if item_id.is_local()
&& !self.effective_visibilities.is_reachable(self.tcx, item_id.expect_def_id())
@@ -118,7 +121,9 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
clean::ImplItem(..) => {}
// tymethods etc. have no control over privacy
clean::TyMethodItem(..) | clean::TyAssocConstItem(..) | clean::TyAssocTypeItem(..) => {}
clean::RequiredMethodItem(..)
| clean::RequiredAssocConstItem(..)
| clean::RequiredAssocTypeItem(..) => {}
// Proc-macros are always public
clean::ProcMacroItem(..) => {}
+5 -4
View File
@@ -35,7 +35,7 @@ fn visit_inner_recur(&mut self, kind: &'a ItemKind) {
| StaticItem(_)
| ConstantItem(..)
| TraitAliasItem(_)
| TyMethodItem(_)
| RequiredMethodItem(_)
| MethodItem(_, _)
| StructFieldItem(_)
| ForeignFunctionItem(..)
@@ -44,9 +44,10 @@ fn visit_inner_recur(&mut self, kind: &'a ItemKind) {
| MacroItem(_)
| ProcMacroItem(_)
| PrimitiveItem(_)
| TyAssocConstItem(..)
| AssocConstItem(..)
| TyAssocTypeItem(..)
| RequiredAssocConstItem(..)
| ProvidedAssocConstItem(..)
| ImplAssocConstItem(..)
| RequiredAssocTypeItem(..)
| AssocTypeItem(..)
| KeywordItem => {}
}
+9 -10
View File
@@ -19,6 +19,7 @@
use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, UintTy};
use rustc_session::config::CrateType;
use rustc_span::{Span, Symbol};
use rustc_target::callconv::{Conv, FnAbi};
use crate::*;
@@ -920,13 +921,11 @@ fn read_wchar_t_str(&self, ptr: Pointer) -> InterpResult<'tcx, Vec<u32>> {
}
/// Check that the ABI is what we expect.
fn check_abi<'a>(&self, abi: ExternAbi, exp_abi: ExternAbi) -> InterpResult<'a, ()> {
if abi != exp_abi {
fn check_abi<'a>(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, exp_abi: Conv) -> InterpResult<'a, ()> {
if fn_abi.conv != exp_abi {
throw_ub_format!(
"calling a function with ABI {} using caller ABI {}",
exp_abi.name(),
abi.name()
)
"calling a function with ABI {:?} using caller ABI {:?}",
exp_abi, fn_abi.conv);
}
interp_ok(())
}
@@ -956,8 +955,8 @@ fn frame_in_std(&self) -> bool {
fn check_abi_and_shim_symbol_clash(
&mut self,
abi: ExternAbi,
exp_abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
exp_abi: Conv,
link_name: Symbol,
) -> InterpResult<'tcx, ()> {
self.check_abi(abi, exp_abi)?;
@@ -981,8 +980,8 @@ fn check_abi_and_shim_symbol_clash(
fn check_shim<'a, const N: usize>(
&mut self,
abi: ExternAbi,
exp_abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
exp_abi: Conv,
link_name: Symbol,
args: &'a [OpTy<'tcx>],
) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]>
+3 -2
View File
@@ -13,6 +13,7 @@
use rustc_abi::{Align, ExternAbi, Size};
use rustc_attr_parsing::InlineAttr;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_target::callconv::FnAbi;
#[allow(unused)]
use rustc_data_structures::static_assert_size;
use rustc_middle::mir;
@@ -1010,7 +1011,7 @@ fn check_fn_target_features(
fn find_mir_or_eval_fn(
ecx: &mut MiriInterpCx<'tcx>,
instance: ty::Instance<'tcx>,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[FnArg<'tcx, Provenance>],
dest: &MPlaceTy<'tcx>,
ret: Option<mir::BasicBlock>,
@@ -1037,7 +1038,7 @@ fn find_mir_or_eval_fn(
fn call_extra_fn(
ecx: &mut MiriInterpCx<'tcx>,
fn_val: DynSym,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[FnArg<'tcx, Provenance>],
dest: &MPlaceTy<'tcx>,
ret: Option<mir::BasicBlock>,
+11 -10
View File
@@ -1,7 +1,8 @@
use rustc_abi::{ExternAbi, Size};
use rustc_abi::Size;
use rustc_middle::ty::layout::LayoutOf as _;
use rustc_middle::ty::{self, Instance, Ty};
use rustc_span::{BytePos, Loc, Symbol, hygiene};
use rustc_target::callconv::{Conv, FnAbi};
use crate::helpers::check_min_arg_count;
use crate::*;
@@ -10,13 +11,13 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn handle_miri_backtrace_size(
&mut self,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
link_name: Symbol,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let [flags] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
let [flags] = this.check_shim(abi, Conv::Rust, link_name, args)?;
let flags = this.read_scalar(flags)?.to_u64()?;
if flags != 0 {
@@ -30,7 +31,7 @@ fn handle_miri_backtrace_size(
fn handle_miri_get_backtrace(
&mut self,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
link_name: Symbol,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
@@ -71,7 +72,7 @@ fn handle_miri_get_backtrace(
// storage for pointers is allocated by miri
// deallocating the slice is undefined behavior with a custom global allocator
0 => {
let [_flags] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
let [_flags] = this.check_shim(abi, Conv::Rust, link_name, args)?;
let alloc = this.allocate(array_layout, MiriMemoryKind::Rust.into())?;
@@ -86,7 +87,7 @@ fn handle_miri_get_backtrace(
}
// storage for pointers is allocated by the caller
1 => {
let [_flags, buf] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
let [_flags, buf] = this.check_shim(abi, Conv::Rust, link_name, args)?;
let buf_place = this.deref_pointer(buf)?;
@@ -136,13 +137,13 @@ fn resolve_frame_pointer(
fn handle_miri_resolve_frame(
&mut self,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
link_name: Symbol,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let [ptr, flags] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
let [ptr, flags] = this.check_shim(abi, Conv::Rust, link_name, args)?;
let flags = this.read_scalar(flags)?.to_u64()?;
@@ -207,14 +208,14 @@ fn handle_miri_resolve_frame(
fn handle_miri_resolve_frame_names(
&mut self,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
link_name: Symbol,
args: &[OpTy<'tcx>],
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let [ptr, flags, name_ptr, filename_ptr] =
this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
this.check_shim(abi, Conv::Rust, link_name, args)?;
let flags = this.read_scalar(flags)?.to_u64()?;
if flags != 0 {
+45 -43
View File
@@ -3,14 +3,17 @@
use std::iter;
use std::path::Path;
use rustc_abi::{Align, AlignFromBytesError, ExternAbi, Size};
use rustc_abi::{Align, AlignFromBytesError, Size};
use rustc_apfloat::Float;
use rustc_ast::expand::allocator::alloc_error_handler_name;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::CrateNum;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::{mir, ty};
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use self::helpers::{ToHost, ToSoft};
use super::alloc::EvalContextExt as _;
@@ -39,7 +42,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_foreign_item(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
ret: Option<mir::BasicBlock>,
@@ -106,7 +109,7 @@ fn is_dyn_sym(&self, name: &str) -> bool {
fn emulate_dyn_sym(
&mut self,
sym: DynSym,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
ret: Option<mir::BasicBlock>,
@@ -218,7 +221,7 @@ fn check_rustc_alloc_request(&self, size: u64, align: u64) -> InterpResult<'tcx>
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -235,11 +238,10 @@ fn emulate_foreign_item_inner(
return interp_ok(EmulateItemResult::NeedsReturn);
}
}
// When adding a new shim, you should follow the following pattern:
// ```
// "shim_name" => {
// let [arg1, arg2, arg3] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
// let [arg1, arg2, arg3] = this.check_shim(abi, Conv::::C , link_name, args)?;
// let result = this.shim_name(arg1, arg2, arg3)?;
// this.write_scalar(result, dest)?;
// }
@@ -277,16 +279,16 @@ fn emulate_foreign_item_inner(
match link_name.as_str() {
// Miri-specific extern functions
"miri_start_unwind" => {
let [payload] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
let [payload] = this.check_shim(abi, Conv::Rust, link_name, args)?;
this.handle_miri_start_unwind(payload)?;
return interp_ok(EmulateItemResult::NeedsUnwind);
}
"miri_run_provenance_gc" => {
let [] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
let [] = this.check_shim(abi, Conv::Rust, link_name, args)?;
this.run_provenance_gc();
}
"miri_get_alloc_id" => {
let [ptr] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
let [ptr] = this.check_shim(abi, Conv::Rust, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr, 0).map_err_kind(|_e| {
err_machine_stop!(TerminationInfo::Abort(format!(
@@ -296,7 +298,7 @@ fn emulate_foreign_item_inner(
this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?;
}
"miri_print_borrow_state" => {
let [id, show_unnamed] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
let [id, show_unnamed] = this.check_shim(abi, Conv::Rust, link_name, args)?;
let id = this.read_scalar(id)?.to_u64()?;
let show_unnamed = this.read_scalar(show_unnamed)?.to_bool()?;
if let Some(id) = std::num::NonZero::new(id).map(AllocId)
@@ -311,7 +313,7 @@ fn emulate_foreign_item_inner(
// This associates a name to a tag. Very useful for debugging, and also makes
// tests more strict.
let [ptr, nth_parent, name] =
this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
this.check_shim(abi, Conv::Rust, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let nth_parent = this.read_scalar(nth_parent)?.to_u8()?;
let name = this.read_immediate(name)?;
@@ -324,7 +326,7 @@ fn emulate_foreign_item_inner(
this.give_pointer_debug_name(ptr, nth_parent, &name)?;
}
"miri_static_root" => {
let [ptr] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
let [ptr] = this.check_shim(abi, Conv::Rust, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let (alloc_id, offset, _) = this.ptr_get_alloc_id(ptr, 0)?;
if offset != Size::ZERO {
@@ -336,7 +338,7 @@ fn emulate_foreign_item_inner(
}
"miri_host_to_target_path" => {
let [ptr, out, out_size] =
this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
this.check_shim(abi, Conv::Rust, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let out = this.read_pointer(out)?;
let out_size = this.read_scalar(out_size)?.to_target_usize(this)?;
@@ -372,7 +374,7 @@ fn emulate_foreign_item_inner(
// Writes some bytes to the interpreter's stdout/stderr. See the
// README for details.
"miri_write_to_stdout" | "miri_write_to_stderr" => {
let [msg] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
let [msg] = this.check_shim(abi, Conv::Rust, link_name, args)?;
let msg = this.read_immediate(msg)?;
let msg = this.read_byte_slice(&msg)?;
// Note: we're ignoring errors writing to host stdout/stderr.
@@ -386,7 +388,7 @@ fn emulate_foreign_item_inner(
"miri_promise_symbolic_alignment" => {
use rustc_abi::AlignFromBytesError;
let [ptr, align] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
let [ptr, align] = this.check_shim(abi, Conv::Rust, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let align = this.read_target_usize(align)?;
if !align.is_power_of_two() {
@@ -428,12 +430,12 @@ fn emulate_foreign_item_inner(
// Aborting the process.
"exit" => {
let [code] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let code = this.read_scalar(code)?.to_i32()?;
throw_machine_stop!(TerminationInfo::Exit { code: code.into(), leak_check: false });
}
"abort" => {
let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [] = this.check_shim(abi, Conv::C , link_name, args)?;
throw_machine_stop!(TerminationInfo::Abort(
"the program aborted execution".to_owned()
))
@@ -442,7 +444,7 @@ fn emulate_foreign_item_inner(
// Standard C allocation
"malloc" => {
let [size] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let size = this.read_target_usize(size)?;
if size <= this.max_size_of_val().bytes() {
let res = this.malloc(size, /*zero_init:*/ false)?;
@@ -457,7 +459,7 @@ fn emulate_foreign_item_inner(
}
"calloc" => {
let [items, elem_size] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let items = this.read_target_usize(items)?;
let elem_size = this.read_target_usize(elem_size)?;
if let Some(size) = this.compute_size_in_bytes(Size::from_bytes(elem_size), items) {
@@ -473,13 +475,13 @@ fn emulate_foreign_item_inner(
}
"free" => {
let [ptr] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let ptr = this.read_pointer(ptr)?;
this.free(ptr)?;
}
"realloc" => {
let [old_ptr, new_size] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let old_ptr = this.read_pointer(old_ptr)?;
let new_size = this.read_target_usize(new_size)?;
if new_size <= this.max_size_of_val().bytes() {
@@ -499,7 +501,7 @@ fn emulate_foreign_item_inner(
let default = |ecx: &mut MiriInterpCx<'tcx>| {
// Only call `check_shim` when `#[global_allocator]` isn't used. When that
// macro is used, we act like no shim exists, so that the exported function can run.
let [size, align] = ecx.check_shim(abi, ExternAbi::Rust, link_name, args)?;
let [size, align] = ecx.check_shim(abi, Conv::Rust, link_name, args)?;
let size = ecx.read_target_usize(size)?;
let align = ecx.read_target_usize(align)?;
@@ -533,7 +535,7 @@ fn emulate_foreign_item_inner(
return this.emulate_allocator(|this| {
// See the comment for `__rust_alloc` why `check_shim` is only called in the
// default case.
let [size, align] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
let [size, align] = this.check_shim(abi, Conv::Rust, link_name, args)?;
let size = this.read_target_usize(size)?;
let align = this.read_target_usize(align)?;
@@ -559,7 +561,7 @@ fn emulate_foreign_item_inner(
// See the comment for `__rust_alloc` why `check_shim` is only called in the
// default case.
let [ptr, old_size, align] =
ecx.check_shim(abi, ExternAbi::Rust, link_name, args)?;
ecx.check_shim(abi, Conv::Rust, link_name, args)?;
let ptr = ecx.read_pointer(ptr)?;
let old_size = ecx.read_target_usize(old_size)?;
let align = ecx.read_target_usize(align)?;
@@ -594,7 +596,7 @@ fn emulate_foreign_item_inner(
// See the comment for `__rust_alloc` why `check_shim` is only called in the
// default case.
let [ptr, old_size, align, new_size] =
this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
this.check_shim(abi, Conv::Rust, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let old_size = this.read_target_usize(old_size)?;
let align = this.read_target_usize(align)?;
@@ -618,7 +620,7 @@ fn emulate_foreign_item_inner(
// C memory handling functions
"memcmp" => {
let [left, right, n] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let left = this.read_pointer(left)?;
let right = this.read_pointer(right)?;
let n = Size::from_bytes(this.read_target_usize(n)?);
@@ -643,7 +645,7 @@ fn emulate_foreign_item_inner(
}
"memrchr" => {
let [ptr, val, num] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let val = this.read_scalar(val)?.to_i32()?;
let num = this.read_target_usize(num)?;
@@ -670,7 +672,7 @@ fn emulate_foreign_item_inner(
}
"memchr" => {
let [ptr, val, num] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let val = this.read_scalar(val)?.to_i32()?;
let num = this.read_target_usize(num)?;
@@ -694,7 +696,7 @@ fn emulate_foreign_item_inner(
}
"strlen" => {
let [ptr] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let ptr = this.read_pointer(ptr)?;
// This reads at least 1 byte, so we are already enforcing that this is a valid pointer.
let n = this.read_c_str(ptr)?.len();
@@ -705,7 +707,7 @@ fn emulate_foreign_item_inner(
}
"wcslen" => {
let [ptr] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let ptr = this.read_pointer(ptr)?;
// This reads at least 1 byte, so we are already enforcing that this is a valid pointer.
let n = this.read_wchar_t_str(ptr)?.len();
@@ -716,7 +718,7 @@ fn emulate_foreign_item_inner(
}
"memcpy" => {
let [ptr_dest, ptr_src, n] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let ptr_dest = this.read_pointer(ptr_dest)?;
let ptr_src = this.read_pointer(ptr_src)?;
let n = this.read_target_usize(n)?;
@@ -731,7 +733,7 @@ fn emulate_foreign_item_inner(
}
"strcpy" => {
let [ptr_dest, ptr_src] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let ptr_dest = this.read_pointer(ptr_dest)?;
let ptr_src = this.read_pointer(ptr_src)?;
@@ -760,7 +762,7 @@ fn emulate_foreign_item_inner(
| "expm1f"
| "tgammaf"
=> {
let [f] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [f] = this.check_shim(abi, Conv::C , link_name, args)?;
let f = this.read_scalar(f)?.to_f32()?;
// Using host floats (but it's fine, these operations do not have guaranteed precision).
let f_host = f.to_host();
@@ -788,7 +790,7 @@ fn emulate_foreign_item_inner(
| "atan2f"
| "fdimf"
=> {
let [f1, f2] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [f1, f2] = this.check_shim(abi, Conv::C , link_name, args)?;
let f1 = this.read_scalar(f1)?.to_f32()?;
let f2 = this.read_scalar(f2)?.to_f32()?;
// underscore case for windows, here and below
@@ -817,7 +819,7 @@ fn emulate_foreign_item_inner(
| "expm1"
| "tgamma"
=> {
let [f] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [f] = this.check_shim(abi, Conv::C , link_name, args)?;
let f = this.read_scalar(f)?.to_f64()?;
// Using host floats (but it's fine, these operations do not have guaranteed precision).
let f_host = f.to_host();
@@ -845,7 +847,7 @@ fn emulate_foreign_item_inner(
| "atan2"
| "fdim"
=> {
let [f1, f2] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [f1, f2] = this.check_shim(abi, Conv::C , link_name, args)?;
let f1 = this.read_scalar(f1)?.to_f64()?;
let f2 = this.read_scalar(f2)?.to_f64()?;
// underscore case for windows, here and below
@@ -866,7 +868,7 @@ fn emulate_foreign_item_inner(
| "ldexp"
| "scalbn"
=> {
let [x, exp] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [x, exp] = this.check_shim(abi, Conv::C , link_name, args)?;
// For radix-2 (binary) systems, `ldexp` and `scalbn` are the same.
let x = this.read_scalar(x)?.to_f64()?;
let exp = this.read_scalar(exp)?.to_i32()?;
@@ -877,7 +879,7 @@ fn emulate_foreign_item_inner(
}
"lgammaf_r" => {
let [x, signp] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let x = this.read_scalar(x)?.to_f32()?;
let signp = this.deref_pointer(signp)?;
@@ -889,7 +891,7 @@ fn emulate_foreign_item_inner(
}
"lgamma_r" => {
let [x, signp] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let x = this.read_scalar(x)?.to_f64()?;
let signp = this.deref_pointer(signp)?;
@@ -903,7 +905,7 @@ fn emulate_foreign_item_inner(
// LLVM intrinsics
"llvm.prefetch" => {
let [p, rw, loc, ty] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let _ = this.read_pointer(p)?;
let rw = this.read_scalar(rw)?.to_i32()?;
@@ -930,7 +932,7 @@ fn emulate_foreign_item_inner(
// Used to implement the x86 `_mm{,256,512}_popcnt_epi{8,16,32,64}` and wasm
// `{i,u}8x16_popcnt` functions.
name if name.starts_with("llvm.ctpop.v") => {
let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [op] = this.check_shim(abi, Conv::C , link_name, args)?;
let (op, op_len) = this.project_to_simd(op)?;
let (dest, dest_len) = this.project_to_simd(dest)?;
@@ -961,7 +963,7 @@ fn emulate_foreign_item_inner(
}
// FIXME: Move these to an `arm` submodule.
"llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => {
let [arg] = this.check_shim(abi, ExternAbi::Unadjusted, link_name, args)?;
let [arg] = this.check_shim(abi, Conv::C, link_name, args)?;
let arg = this.read_scalar(arg)?.to_i32()?;
match arg {
// SY ("full system scope")
@@ -974,7 +976,7 @@ fn emulate_foreign_item_inner(
}
}
"llvm.arm.hint" if this.tcx.sess.target.arch == "arm" => {
let [arg] = this.check_shim(abi, ExternAbi::Unadjusted, link_name, args)?;
let [arg] = this.check_shim(abi, Conv::C, link_name, args)?;
let arg = this.read_scalar(arg)?.to_i32()?;
// Note that different arguments might have different target feature requirements.
match arg {
@@ -1,5 +1,8 @@
use rustc_abi::ExternAbi;
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use crate::shims::unix::android::thread::prctl;
use crate::shims::unix::linux_like::epoll::EvalContextExt as _;
@@ -16,7 +19,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -25,31 +28,31 @@ fn emulate_foreign_item_inner(
// epoll, eventfd
"epoll_create1" => {
let [flag] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.epoll_create1(flag)?;
this.write_scalar(result, dest)?;
}
"epoll_ctl" => {
let [epfd, op, fd, event] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.epoll_ctl(epfd, op, fd, event)?;
this.write_scalar(result, dest)?;
}
"epoll_wait" => {
let [epfd, events, maxevents, timeout] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
this.epoll_wait(epfd, events, maxevents, timeout, dest)?;
}
"eventfd" => {
let [val, flag] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.eventfd(val, flag)?;
this.write_scalar(result, dest)?;
}
// Miscellaneous
"__errno" => {
let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [] = this.check_shim(abi, Conv::C, link_name, args)?;
let errno_place = this.last_error_place()?;
this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
}
@@ -1,5 +1,7 @@
use rustc_abi::{ExternAbi, Size};
use rustc_abi::Size;
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use crate::helpers::check_min_arg_count;
use crate::shims::unix::thread::{EvalContextExt as _, ThreadNameResult};
@@ -10,13 +12,13 @@
pub fn prctl<'tcx>(
ecx: &mut MiriInterpCx<'tcx>,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx> {
// We do not use `check_shim` here because `prctl` is variadic. The argument
// count is checked bellow.
ecx.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?;
ecx.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?;
// FIXME: Use constants once https://github.com/rust-lang/libc/pull/3941 backported to the 0.2 branch.
let pr_set_name = 15;
+103 -103
View File
@@ -1,9 +1,11 @@
use std::ffi::OsStr;
use std::str;
use rustc_abi::{ExternAbi, Size};
use rustc_abi::Size;
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use self::shims::unix::android::foreign_items as android;
use self::shims::unix::freebsd::foreign_items as freebsd;
@@ -100,7 +102,7 @@ fn strerror_r(
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -111,54 +113,52 @@ fn emulate_foreign_item_inner(
match link_name.as_str() {
// Environment related shims
"getenv" => {
let [name] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [name] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.getenv(name)?;
this.write_pointer(result, dest)?;
}
"unsetenv" => {
let [name] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [name] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.unsetenv(name)?;
this.write_scalar(result, dest)?;
}
"setenv" => {
let [name, value, overwrite] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [name, value, overwrite] = this.check_shim(abi, Conv::C , link_name, args)?;
this.read_scalar(overwrite)?.to_i32()?;
let result = this.setenv(name, value)?;
this.write_scalar(result, dest)?;
}
"getcwd" => {
let [buf, size] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [buf, size] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.getcwd(buf, size)?;
this.write_pointer(result, dest)?;
}
"chdir" => {
let [path] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [path] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.chdir(path)?;
this.write_scalar(result, dest)?;
}
"getpid" => {
let [] = this.check_shim(abi, ExternAbi::C { unwind: false}, link_name, args)?;
let [] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.getpid()?;
this.write_scalar(result, dest)?;
}
"sysconf" => {
let [val] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.sysconf(val)?;
this.write_scalar(result, dest)?;
}
// File descriptors
"read" => {
let [fd, buf, count] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [fd, buf, count] = this.check_shim(abi, Conv::C , link_name, args)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let buf = this.read_pointer(buf)?;
let count = this.read_target_usize(count)?;
this.read(fd, buf, count, None, dest)?;
}
"write" => {
let [fd, buf, n] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [fd, buf, n] = this.check_shim(abi, Conv::C , link_name, args)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let buf = this.read_pointer(buf)?;
let count = this.read_target_usize(n)?;
@@ -166,7 +166,7 @@ fn emulate_foreign_item_inner(
this.write(fd, buf, count, None, dest)?;
}
"pread" => {
let [fd, buf, count, offset] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [fd, buf, count, offset] = this.check_shim(abi, Conv::C , link_name, args)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let buf = this.read_pointer(buf)?;
let count = this.read_target_usize(count)?;
@@ -174,7 +174,7 @@ fn emulate_foreign_item_inner(
this.read(fd, buf, count, Some(offset), dest)?;
}
"pwrite" => {
let [fd, buf, n, offset] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [fd, buf, n, offset] = this.check_shim(abi, Conv::C , link_name, args)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let buf = this.read_pointer(buf)?;
let count = this.read_target_usize(n)?;
@@ -183,7 +183,7 @@ fn emulate_foreign_item_inner(
this.write(fd, buf, count, Some(offset), dest)?;
}
"pread64" => {
let [fd, buf, count, offset] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [fd, buf, count, offset] = this.check_shim(abi, Conv::C , link_name, args)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let buf = this.read_pointer(buf)?;
let count = this.read_target_usize(count)?;
@@ -191,7 +191,7 @@ fn emulate_foreign_item_inner(
this.read(fd, buf, count, Some(offset), dest)?;
}
"pwrite64" => {
let [fd, buf, n, offset] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [fd, buf, n, offset] = this.check_shim(abi, Conv::C , link_name, args)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let buf = this.read_pointer(buf)?;
let count = this.read_target_usize(n)?;
@@ -200,32 +200,32 @@ fn emulate_foreign_item_inner(
this.write(fd, buf, count, Some(offset), dest)?;
}
"close" => {
let [fd] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [fd] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.close(fd)?;
this.write_scalar(result, dest)?;
}
"fcntl" => {
// `fcntl` is variadic. The argument count is checked based on the first argument
// in `this.fcntl()`, so we do not use `check_shim` here.
this.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?;
this.check_abi_and_shim_symbol_clash(abi, Conv::C , link_name)?;
let result = this.fcntl(args)?;
this.write_scalar(result, dest)?;
}
"dup" => {
let [old_fd] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [old_fd] = this.check_shim(abi, Conv::C , link_name, args)?;
let old_fd = this.read_scalar(old_fd)?.to_i32()?;
let new_fd = this.dup(old_fd)?;
this.write_scalar(new_fd, dest)?;
}
"dup2" => {
let [old_fd, new_fd] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [old_fd, new_fd] = this.check_shim(abi, Conv::C , link_name, args)?;
let old_fd = this.read_scalar(old_fd)?.to_i32()?;
let new_fd = this.read_scalar(new_fd)?.to_i32()?;
let result = this.dup2(old_fd, new_fd)?;
this.write_scalar(result, dest)?;
}
"flock" => {
let [fd, op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [fd, op] = this.check_shim(abi, Conv::C , link_name, args)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let op = this.read_scalar(op)?.to_i32()?;
let result = this.flock(fd, op)?;
@@ -235,47 +235,47 @@ fn emulate_foreign_item_inner(
// File and file system access
"open" | "open64" => {
// `open` is variadic, the third argument is only present when the second argument has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set
this.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?;
this.check_abi_and_shim_symbol_clash(abi, Conv::C , link_name)?;
let result = this.open(args)?;
this.write_scalar(result, dest)?;
}
"unlink" => {
let [path] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [path] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.unlink(path)?;
this.write_scalar(result, dest)?;
}
"symlink" => {
let [target, linkpath] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [target, linkpath] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.symlink(target, linkpath)?;
this.write_scalar(result, dest)?;
}
"rename" => {
let [oldpath, newpath] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [oldpath, newpath] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.rename(oldpath, newpath)?;
this.write_scalar(result, dest)?;
}
"mkdir" => {
let [path, mode] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [path, mode] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.mkdir(path, mode)?;
this.write_scalar(result, dest)?;
}
"rmdir" => {
let [path] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [path] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.rmdir(path)?;
this.write_scalar(result, dest)?;
}
"opendir" => {
let [name] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [name] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.opendir(name)?;
this.write_scalar(result, dest)?;
}
"closedir" => {
let [dirp] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [dirp] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.closedir(dirp)?;
this.write_scalar(result, dest)?;
}
"lseek64" => {
let [fd, offset, whence] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [fd, offset, whence] = this.check_shim(abi, Conv::C , link_name, args)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let offset = this.read_scalar(offset)?.to_i64()?;
let whence = this.read_scalar(whence)?.to_i32()?;
@@ -283,7 +283,7 @@ fn emulate_foreign_item_inner(
this.write_scalar(result, dest)?;
}
"lseek" => {
let [fd, offset, whence] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [fd, offset, whence] = this.check_shim(abi, Conv::C , link_name, args)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
let whence = this.read_scalar(whence)?.to_i32()?;
@@ -292,7 +292,7 @@ fn emulate_foreign_item_inner(
}
"ftruncate64" => {
let [fd, length] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let length = this.read_scalar(length)?.to_i64()?;
let result = this.ftruncate64(fd, length.into())?;
@@ -300,30 +300,30 @@ fn emulate_foreign_item_inner(
}
"ftruncate" => {
let [fd, length] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let length = this.read_scalar(length)?.to_int(this.libc_ty_layout("off_t").size)?;
let result = this.ftruncate64(fd, length)?;
this.write_scalar(result, dest)?;
}
"fsync" => {
let [fd] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [fd] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.fsync(fd)?;
this.write_scalar(result, dest)?;
}
"fdatasync" => {
let [fd] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [fd] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.fdatasync(fd)?;
this.write_scalar(result, dest)?;
}
"readlink" => {
let [pathname, buf, bufsize] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [pathname, buf, bufsize] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.readlink(pathname, buf, bufsize)?;
this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
}
"posix_fadvise" => {
let [fd, offset, len, advice] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
this.read_scalar(fd)?.to_i32()?;
this.read_target_isize(offset)?;
this.read_target_isize(len)?;
@@ -332,12 +332,12 @@ fn emulate_foreign_item_inner(
this.write_null(dest)?;
}
"realpath" => {
let [path, resolved_path] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [path, resolved_path] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.realpath(path, resolved_path)?;
this.write_scalar(result, dest)?;
}
"mkstemp" => {
let [template] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [template] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.mkstemp(template)?;
this.write_scalar(result, dest)?;
}
@@ -345,13 +345,13 @@ fn emulate_foreign_item_inner(
// Unnamed sockets and pipes
"socketpair" => {
let [domain, type_, protocol, sv] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.socketpair(domain, type_, protocol, sv)?;
this.write_scalar(result, dest)?;
}
"pipe" => {
let [pipefd] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.pipe2(pipefd, /*flags*/ None)?;
this.write_scalar(result, dest)?;
}
@@ -364,44 +364,44 @@ fn emulate_foreign_item_inner(
);
}
let [pipefd, flags] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.pipe2(pipefd, Some(flags))?;
this.write_scalar(result, dest)?;
}
// Time
"gettimeofday" => {
let [tv, tz] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [tv, tz] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.gettimeofday(tv, tz)?;
this.write_scalar(result, dest)?;
}
"localtime_r" => {
let [timep, result_op] = this.check_shim(abi, ExternAbi::C {unwind: false}, link_name, args)?;
let [timep, result_op] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.localtime_r(timep, result_op)?;
this.write_pointer(result, dest)?;
}
"clock_gettime" => {
let [clk_id, tp] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.clock_gettime(clk_id, tp)?;
this.write_scalar(result, dest)?;
}
// Allocation
"posix_memalign" => {
let [memptr, align, size] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [memptr, align, size] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.posix_memalign(memptr, align, size)?;
this.write_scalar(result, dest)?;
}
"mmap" => {
let [addr, length, prot, flags, fd, offset] = this.check_shim(abi, ExternAbi::C {unwind: false}, link_name, args)?;
let [addr, length, prot, flags, fd, offset] = this.check_shim(abi, Conv::C , link_name, args)?;
let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
let ptr = this.mmap(addr, length, prot, flags, fd, offset)?;
this.write_scalar(ptr, dest)?;
}
"munmap" => {
let [addr, length] = this.check_shim(abi, ExternAbi::C {unwind: false}, link_name, args)?;
let [addr, length] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.munmap(addr, length)?;
this.write_scalar(result, dest)?;
}
@@ -415,7 +415,7 @@ fn emulate_foreign_item_inner(
);
}
let [ptr, nmemb, size] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let nmemb = this.read_target_usize(nmemb)?;
let size = this.read_target_usize(size)?;
@@ -439,14 +439,14 @@ fn emulate_foreign_item_inner(
// This is a C11 function, we assume all Unixes have it.
// (MSVC explicitly does not support this.)
let [align, size] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let res = this.aligned_alloc(align, size)?;
this.write_pointer(res, dest)?;
}
// Dynamic symbol loading
"dlsym" => {
let [handle, symbol] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [handle, symbol] = this.check_shim(abi, Conv::C , link_name, args)?;
this.read_target_usize(handle)?;
let symbol = this.read_pointer(symbol)?;
let name = this.read_c_str(symbol)?;
@@ -460,7 +460,7 @@ fn emulate_foreign_item_inner(
// Thread-local storage
"pthread_key_create" => {
let [key, dtor] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [key, dtor] = this.check_shim(abi, Conv::C , link_name, args)?;
let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?;
let dtor = this.read_pointer(dtor)?;
@@ -488,21 +488,21 @@ fn emulate_foreign_item_inner(
this.write_null(dest)?;
}
"pthread_key_delete" => {
let [key] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [key] = this.check_shim(abi, Conv::C , link_name, args)?;
let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
this.machine.tls.delete_tls_key(key)?;
// Return success (0)
this.write_null(dest)?;
}
"pthread_getspecific" => {
let [key] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [key] = this.check_shim(abi, Conv::C , link_name, args)?;
let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
let active_thread = this.active_thread();
let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
this.write_scalar(ptr, dest)?;
}
"pthread_setspecific" => {
let [key, new_ptr] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [key, new_ptr] = this.check_shim(abi, Conv::C , link_name, args)?;
let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
let active_thread = this.active_thread();
let new_data = this.read_scalar(new_ptr)?;
@@ -514,151 +514,151 @@ fn emulate_foreign_item_inner(
// Synchronization primitives
"pthread_mutexattr_init" => {
let [attr] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [attr] = this.check_shim(abi, Conv::C , link_name, args)?;
this.pthread_mutexattr_init(attr)?;
this.write_null(dest)?;
}
"pthread_mutexattr_settype" => {
let [attr, kind] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [attr, kind] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.pthread_mutexattr_settype(attr, kind)?;
this.write_scalar(result, dest)?;
}
"pthread_mutexattr_destroy" => {
let [attr] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [attr] = this.check_shim(abi, Conv::C , link_name, args)?;
this.pthread_mutexattr_destroy(attr)?;
this.write_null(dest)?;
}
"pthread_mutex_init" => {
let [mutex, attr] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [mutex, attr] = this.check_shim(abi, Conv::C , link_name, args)?;
this.pthread_mutex_init(mutex, attr)?;
this.write_null(dest)?;
}
"pthread_mutex_lock" => {
let [mutex] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?;
this.pthread_mutex_lock(mutex, dest)?;
}
"pthread_mutex_trylock" => {
let [mutex] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.pthread_mutex_trylock(mutex)?;
this.write_scalar(result, dest)?;
}
"pthread_mutex_unlock" => {
let [mutex] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.pthread_mutex_unlock(mutex)?;
this.write_scalar(result, dest)?;
}
"pthread_mutex_destroy" => {
let [mutex] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?;
this.pthread_mutex_destroy(mutex)?;
this.write_int(0, dest)?;
}
"pthread_rwlock_rdlock" => {
let [rwlock] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?;
this.pthread_rwlock_rdlock(rwlock, dest)?;
}
"pthread_rwlock_tryrdlock" => {
let [rwlock] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.pthread_rwlock_tryrdlock(rwlock)?;
this.write_scalar(result, dest)?;
}
"pthread_rwlock_wrlock" => {
let [rwlock] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?;
this.pthread_rwlock_wrlock(rwlock, dest)?;
}
"pthread_rwlock_trywrlock" => {
let [rwlock] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.pthread_rwlock_trywrlock(rwlock)?;
this.write_scalar(result, dest)?;
}
"pthread_rwlock_unlock" => {
let [rwlock] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?;
this.pthread_rwlock_unlock(rwlock)?;
this.write_null(dest)?;
}
"pthread_rwlock_destroy" => {
let [rwlock] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?;
this.pthread_rwlock_destroy(rwlock)?;
this.write_null(dest)?;
}
"pthread_condattr_init" => {
let [attr] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [attr] = this.check_shim(abi, Conv::C , link_name, args)?;
this.pthread_condattr_init(attr)?;
this.write_null(dest)?;
}
"pthread_condattr_setclock" => {
let [attr, clock_id] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.pthread_condattr_setclock(attr, clock_id)?;
this.write_scalar(result, dest)?;
}
"pthread_condattr_getclock" => {
let [attr, clock_id] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
this.pthread_condattr_getclock(attr, clock_id)?;
this.write_null(dest)?;
}
"pthread_condattr_destroy" => {
let [attr] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [attr] = this.check_shim(abi, Conv::C , link_name, args)?;
this.pthread_condattr_destroy(attr)?;
this.write_null(dest)?;
}
"pthread_cond_init" => {
let [cond, attr] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [cond, attr] = this.check_shim(abi, Conv::C , link_name, args)?;
this.pthread_cond_init(cond, attr)?;
this.write_null(dest)?;
}
"pthread_cond_signal" => {
let [cond] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [cond] = this.check_shim(abi, Conv::C , link_name, args)?;
this.pthread_cond_signal(cond)?;
this.write_null(dest)?;
}
"pthread_cond_broadcast" => {
let [cond] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [cond] = this.check_shim(abi, Conv::C , link_name, args)?;
this.pthread_cond_broadcast(cond)?;
this.write_null(dest)?;
}
"pthread_cond_wait" => {
let [cond, mutex] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [cond, mutex] = this.check_shim(abi, Conv::C , link_name, args)?;
this.pthread_cond_wait(cond, mutex, dest)?;
}
"pthread_cond_timedwait" => {
let [cond, mutex, abstime] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [cond, mutex, abstime] = this.check_shim(abi, Conv::C , link_name, args)?;
this.pthread_cond_timedwait(cond, mutex, abstime, dest)?;
}
"pthread_cond_destroy" => {
let [cond] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [cond] = this.check_shim(abi, Conv::C , link_name, args)?;
this.pthread_cond_destroy(cond)?;
this.write_null(dest)?;
}
// Threading
"pthread_create" => {
let [thread, attr, start, arg] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [thread, attr, start, arg] = this.check_shim(abi, Conv::C , link_name, args)?;
this.pthread_create(thread, attr, start, arg)?;
this.write_null(dest)?;
}
"pthread_join" => {
let [thread, retval] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [thread, retval] = this.check_shim(abi, Conv::C , link_name, args)?;
let res = this.pthread_join(thread, retval)?;
this.write_scalar(res, dest)?;
}
"pthread_detach" => {
let [thread] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [thread] = this.check_shim(abi, Conv::C , link_name, args)?;
let res = this.pthread_detach(thread)?;
this.write_scalar(res, dest)?;
}
"pthread_self" => {
let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [] = this.check_shim(abi, Conv::C , link_name, args)?;
let res = this.pthread_self()?;
this.write_scalar(res, dest)?;
}
"sched_yield" => {
let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [] = this.check_shim(abi, Conv::C , link_name, args)?;
this.sched_yield()?;
this.write_null(dest)?;
}
"nanosleep" => {
let [req, rem] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [req, rem] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.nanosleep(req, rem)?;
this.write_scalar(result, dest)?;
}
@@ -672,7 +672,7 @@ fn emulate_foreign_item_inner(
}
let [pid, cpusetsize, mask] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let pid = this.read_scalar(pid)?.to_u32()?;
let cpusetsize = this.read_target_usize(cpusetsize)?;
let mask = this.read_pointer(mask)?;
@@ -712,7 +712,7 @@ fn emulate_foreign_item_inner(
}
let [pid, cpusetsize, mask] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let pid = this.read_scalar(pid)?.to_u32()?;
let cpusetsize = this.read_target_usize(cpusetsize)?;
let mask = this.read_pointer(mask)?;
@@ -748,12 +748,12 @@ fn emulate_foreign_item_inner(
// Miscellaneous
"isatty" => {
let [fd] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [fd] = this.check_shim(abi, Conv::C , link_name, args)?;
let result = this.isatty(fd)?;
this.write_scalar(result, dest)?;
}
"pthread_atfork" => {
let [prepare, parent, child] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [prepare, parent, child] = this.check_shim(abi, Conv::C , link_name, args)?;
this.read_pointer(prepare)?;
this.read_pointer(parent)?;
this.read_pointer(child)?;
@@ -771,7 +771,7 @@ fn emulate_foreign_item_inner(
}
let [buf, bufsize] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let buf = this.read_pointer(buf)?;
let bufsize = this.read_target_usize(bufsize)?;
@@ -790,7 +790,7 @@ fn emulate_foreign_item_inner(
"strerror_r" => {
let [errnum, buf, buflen] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.strerror_r(errnum, buf, buflen)?;
this.write_scalar(result, dest)?;
}
@@ -805,7 +805,7 @@ fn emulate_foreign_item_inner(
);
}
let [ptr, len, flags] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let len = this.read_target_usize(len)?;
let _flags = this.read_scalar(flags)?.to_i32()?;
@@ -822,7 +822,7 @@ fn emulate_foreign_item_inner(
this.tcx.sess.target.os
);
}
let [ptr, len] = this.check_shim(abi, ExternAbi::C { unwind: false}, link_name, args)?;
let [ptr, len] = this.check_shim(abi, Conv::C , link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let len = this.read_target_usize(len)?;
this.gen_random(ptr, len)?;
@@ -848,12 +848,12 @@ fn emulate_foreign_item_inner(
);
}
// This function looks and behaves excatly like miri_start_unwind.
let [payload] = this.check_shim(abi, ExternAbi::C { unwind: true }, link_name, args)?;
let [payload] = this.check_shim(abi, Conv::C, link_name, args)?;
this.handle_miri_start_unwind(payload)?;
return interp_ok(EmulateItemResult::NeedsUnwind);
}
"getuid" => {
let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [] = this.check_shim(abi, Conv::C , link_name, args)?;
// For now, just pretend we always have this fixed UID.
this.write_int(UID, dest)?;
}
@@ -862,7 +862,7 @@ fn emulate_foreign_item_inner(
// These shims are enabled only when the caller is in the standard library.
"pthread_attr_getguardsize"
if this.frame_in_std() => {
let [_attr, guard_size] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [_attr, guard_size] = this.check_shim(abi, Conv::C , link_name, args)?;
let guard_size = this.deref_pointer(guard_size)?;
let guard_size_layout = this.libc_ty_layout("size_t");
this.write_scalar(Scalar::from_uint(this.machine.page_size, guard_size_layout.size), &guard_size)?;
@@ -874,12 +874,12 @@ fn emulate_foreign_item_inner(
| "pthread_attr_init"
| "pthread_attr_destroy"
if this.frame_in_std() => {
let [_] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [_] = this.check_shim(abi, Conv::C , link_name, args)?;
this.write_null(dest)?;
}
| "pthread_attr_setstacksize"
if this.frame_in_std() => {
let [_, _] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [_, _] = this.check_shim(abi, Conv::C , link_name, args)?;
this.write_null(dest)?;
}
@@ -888,7 +888,7 @@ fn emulate_foreign_item_inner(
// We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here.
// Hence we can mostly ignore the input `attr_place`.
let [attr_place, addr_place, size_place] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
let _attr_place = this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
let addr_place = this.deref_pointer(addr_place)?;
let size_place = this.deref_pointer(size_place)?;
@@ -909,13 +909,13 @@ fn emulate_foreign_item_inner(
| "signal"
| "sigaltstack"
if this.frame_in_std() => {
let [_, _] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [_, _] = this.check_shim(abi, Conv::C , link_name, args)?;
this.write_null(dest)?;
}
| "sigaction"
| "mprotect"
if this.frame_in_std() => {
let [_, _, _] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [_, _, _] = this.check_shim(abi, Conv::C , link_name, args)?;
this.write_null(dest)?;
}
@@ -923,7 +923,7 @@ fn emulate_foreign_item_inner(
if this.frame_in_std() => {
// getpwuid_r is the standard name, __posix_getpwuid_r is used on solarish
let [uid, pwd, buf, buflen, result] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C , link_name, args)?;
this.check_no_isolation("`getpwuid_r`")?;
let uid = this.read_scalar(uid)?.to_u32()?;
@@ -1,5 +1,6 @@
use rustc_abi::ExternAbi;
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use crate::shims::unix::*;
use crate::*;
@@ -13,7 +14,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -22,7 +23,7 @@ fn emulate_foreign_item_inner(
// Threading
"pthread_set_name_np" => {
let [thread, name] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let max_len = usize::MAX; // FreeBSD does not seem to have a limit.
// FreeBSD's pthread_set_name_np does not return anything.
this.pthread_setname_np(
@@ -34,7 +35,7 @@ fn emulate_foreign_item_inner(
}
"pthread_get_name_np" => {
let [thread, name, len] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
// FreeBSD's pthread_get_name_np does not return anything
// and uses strlcpy, which truncates the resulting value,
// but always adds a null terminator (except for zero-sized buffers).
@@ -52,32 +53,32 @@ fn emulate_foreign_item_inner(
// since freebsd 12 the former form can be expected.
"stat" | "stat@FBSD_1.0" => {
let [path, buf] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.macos_fbsd_solaris_stat(path, buf)?;
this.write_scalar(result, dest)?;
}
"lstat" | "lstat@FBSD_1.0" => {
let [path, buf] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.macos_fbsd_solaris_lstat(path, buf)?;
this.write_scalar(result, dest)?;
}
"fstat" | "fstat@FBSD_1.0" => {
let [fd, buf] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.macos_fbsd_solaris_fstat(fd, buf)?;
this.write_scalar(result, dest)?;
}
"readdir_r" | "readdir_r@FBSD_1.0" => {
let [dirp, entry, result] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.macos_fbsd_readdir_r(dirp, entry, result)?;
this.write_scalar(result, dest)?;
}
// Miscellaneous
"__error" => {
let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [] = this.check_shim(abi, Conv::C, link_name, args)?;
let errno_place = this.last_error_place()?;
this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
}
@@ -86,7 +87,7 @@ fn emulate_foreign_item_inner(
// These shims are enabled only when the caller is in the standard library.
"pthread_attr_get_np" if this.frame_in_std() => {
let [_thread, _attr] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
this.write_null(dest)?;
}
@@ -1,5 +1,6 @@
use rustc_abi::ExternAbi;
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use self::shims::unix::linux::mem::EvalContextExt as _;
use self::shims::unix::linux_like::epoll::EvalContextExt as _;
@@ -24,7 +25,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -36,19 +37,19 @@ fn emulate_foreign_item_inner(
// File related shims
"readdir64" => {
let [dirp] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.linux_solarish_readdir64("dirent64", dirp)?;
this.write_scalar(result, dest)?;
}
"sync_file_range" => {
let [fd, offset, nbytes, flags] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.sync_file_range(fd, offset, nbytes, flags)?;
this.write_scalar(result, dest)?;
}
"statx" => {
let [dirfd, pathname, flags, mask, statxbuf] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?;
this.write_scalar(result, dest)?;
}
@@ -56,24 +57,24 @@ fn emulate_foreign_item_inner(
// epoll, eventfd
"epoll_create1" => {
let [flag] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.epoll_create1(flag)?;
this.write_scalar(result, dest)?;
}
"epoll_ctl" => {
let [epfd, op, fd, event] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.epoll_ctl(epfd, op, fd, event)?;
this.write_scalar(result, dest)?;
}
"epoll_wait" => {
let [epfd, events, maxevents, timeout] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
this.epoll_wait(epfd, events, maxevents, timeout, dest)?;
}
"eventfd" => {
let [val, flag] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.eventfd(val, flag)?;
this.write_scalar(result, dest)?;
}
@@ -81,7 +82,7 @@ fn emulate_foreign_item_inner(
// Threading
"pthread_setname_np" => {
let [thread, name] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let res = match this.pthread_setname_np(
this.read_scalar(thread)?,
this.read_scalar(name)?,
@@ -97,7 +98,7 @@ fn emulate_foreign_item_inner(
}
"pthread_getname_np" => {
let [thread, name, len] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
// The function's behavior isn't portable between platforms.
// In case of glibc, the length of the output buffer must
// be not shorter than TASK_COMM_LEN.
@@ -120,7 +121,7 @@ fn emulate_foreign_item_inner(
this.write_scalar(res, dest)?;
}
"gettid" => {
let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [] = this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.linux_gettid()?;
this.write_scalar(result, dest)?;
}
@@ -133,35 +134,35 @@ fn emulate_foreign_item_inner(
// Miscellaneous
"mmap64" => {
let [addr, length, prot, flags, fd, offset] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let offset = this.read_scalar(offset)?.to_i64()?;
let ptr = this.mmap(addr, length, prot, flags, fd, offset.into())?;
this.write_scalar(ptr, dest)?;
}
"mremap" => {
let [old_address, old_size, new_size, flags] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let ptr = this.mremap(old_address, old_size, new_size, flags)?;
this.write_scalar(ptr, dest)?;
}
"__xpg_strerror_r" => {
let [errnum, buf, buflen] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.strerror_r(errnum, buf, buflen)?;
this.write_scalar(result, dest)?;
}
"__errno_location" => {
let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [] = this.check_shim(abi, Conv::C, link_name, args)?;
let errno_place = this.last_error_place()?;
this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
}
"__libc_current_sigrtmin" => {
let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [] = this.check_shim(abi, Conv::C, link_name, args)?;
this.write_int(SIGRTMIN, dest)?;
}
"__libc_current_sigrtmax" => {
let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [] = this.check_shim(abi, Conv::C, link_name, args)?;
this.write_int(SIGRTMAX, dest)?;
}
@@ -170,7 +171,7 @@ fn emulate_foreign_item_inner(
// These shims are enabled only when the caller is in the standard library.
"pthread_getattr_np" if this.frame_in_std() => {
let [_thread, _attr] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
this.write_null(dest)?;
}
@@ -1,5 +1,7 @@
use rustc_abi::ExternAbi;
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use crate::helpers::check_min_arg_count;
use crate::shims::unix::linux_like::eventfd::EvalContextExt as _;
@@ -9,13 +11,13 @@
pub fn syscall<'tcx>(
ecx: &mut MiriInterpCx<'tcx>,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx> {
// We do not use `check_shim` here because `syscall` is variadic. The argument
// count is checked bellow.
ecx.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?;
ecx.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?;
// The syscall variadic function is legal to call with more arguments than needed,
// extra arguments are simply ignored. The important check is that when we use an
// argument, we have to also check all arguments *before* it to ensure that they
@@ -1,5 +1,6 @@
use rustc_abi::ExternAbi;
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use super::sync::EvalContextExt as _;
use crate::shims::unix::*;
@@ -14,7 +15,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -25,7 +26,7 @@ fn emulate_foreign_item_inner(
match link_name.as_str() {
// errno
"__error" => {
let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [] = this.check_shim(abi, Conv::C, link_name, args)?;
let errno_place = this.last_error_place()?;
this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
}
@@ -33,50 +34,50 @@ fn emulate_foreign_item_inner(
// File related shims
"close$NOCANCEL" => {
let [result] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.close(result)?;
this.write_scalar(result, dest)?;
}
"stat" | "stat64" | "stat$INODE64" => {
let [path, buf] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.macos_fbsd_solaris_stat(path, buf)?;
this.write_scalar(result, dest)?;
}
"lstat" | "lstat64" | "lstat$INODE64" => {
let [path, buf] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.macos_fbsd_solaris_lstat(path, buf)?;
this.write_scalar(result, dest)?;
}
"fstat" | "fstat64" | "fstat$INODE64" => {
let [fd, buf] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.macos_fbsd_solaris_fstat(fd, buf)?;
this.write_scalar(result, dest)?;
}
"opendir$INODE64" => {
let [name] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.opendir(name)?;
this.write_scalar(result, dest)?;
}
"readdir_r" | "readdir_r$INODE64" => {
let [dirp, entry, result] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.macos_fbsd_readdir_r(dirp, entry, result)?;
this.write_scalar(result, dest)?;
}
"realpath$DARWIN_EXTSN" => {
let [path, resolved_path] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.realpath(path, resolved_path)?;
this.write_scalar(result, dest)?;
}
// Environment related shims
"_NSGetEnviron" => {
let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [] = this.check_shim(abi, Conv::C, link_name, args)?;
let environ = this.machine.env_vars.unix().environ();
this.write_pointer(environ, dest)?;
}
@@ -84,7 +85,7 @@ fn emulate_foreign_item_inner(
// Random data generation
"CCRandomGenerateBytes" => {
let [bytes, count] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let bytes = this.read_pointer(bytes)?;
let count = this.read_target_usize(count)?;
let success = this.eval_libc_i32("kCCSuccess");
@@ -94,30 +95,30 @@ fn emulate_foreign_item_inner(
// Time related shims
"mach_absolute_time" => {
let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [] = this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.mach_absolute_time()?;
this.write_scalar(result, dest)?;
}
"mach_timebase_info" => {
let [info] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.mach_timebase_info(info)?;
this.write_scalar(result, dest)?;
}
// Access to command-line arguments
"_NSGetArgc" => {
let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [] = this.check_shim(abi, Conv::C, link_name, args)?;
this.write_pointer(this.machine.argc.expect("machine must be initialized"), dest)?;
}
"_NSGetArgv" => {
let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [] = this.check_shim(abi, Conv::C, link_name, args)?;
this.write_pointer(this.machine.argv.expect("machine must be initialized"), dest)?;
}
"_NSGetExecutablePath" => {
let [buf, bufsize] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
this.check_no_isolation("`_NSGetExecutablePath`")?;
let buf_ptr = this.read_pointer(buf)?;
@@ -143,7 +144,7 @@ fn emulate_foreign_item_inner(
// Thread-local storage
"_tlv_atexit" => {
let [dtor, data] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let dtor = this.read_pointer(dtor)?;
let dtor = this.get_ptr_fn(dtor)?.as_instance()?;
let data = this.read_scalar(data)?;
@@ -154,14 +155,14 @@ fn emulate_foreign_item_inner(
// Querying system information
"pthread_get_stackaddr_np" => {
let [thread] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
this.read_target_usize(thread)?;
let stack_addr = Scalar::from_uint(this.machine.stack_addr, this.pointer_size());
this.write_scalar(stack_addr, dest)?;
}
"pthread_get_stacksize_np" => {
let [thread] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
this.read_target_usize(thread)?;
let stack_size = Scalar::from_uint(this.machine.stack_size, this.pointer_size());
this.write_scalar(stack_size, dest)?;
@@ -170,7 +171,7 @@ fn emulate_foreign_item_inner(
// Threading
"pthread_setname_np" => {
let [name] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
// The real implementation has logic in two places:
// * in userland at https://github.com/apple-oss-distributions/libpthread/blob/c032e0b076700a0a47db75528a282b8d3a06531a/src/pthread.c#L1178-L1200,
@@ -198,7 +199,7 @@ fn emulate_foreign_item_inner(
}
"pthread_getname_np" => {
let [thread, name, len] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
// The function's behavior isn't portable between platforms.
// In case of macOS, a truncated name (due to a too small buffer)
@@ -224,27 +225,27 @@ fn emulate_foreign_item_inner(
"os_unfair_lock_lock" => {
let [lock_op] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
this.os_unfair_lock_lock(lock_op)?;
}
"os_unfair_lock_trylock" => {
let [lock_op] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
this.os_unfair_lock_trylock(lock_op, dest)?;
}
"os_unfair_lock_unlock" => {
let [lock_op] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
this.os_unfair_lock_unlock(lock_op)?;
}
"os_unfair_lock_assert_owner" => {
let [lock_op] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
this.os_unfair_lock_assert_owner(lock_op)?;
}
"os_unfair_lock_assert_not_owner" => {
let [lock_op] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
this.os_unfair_lock_assert_not_owner(lock_op)?;
}
@@ -1,5 +1,6 @@
use rustc_abi::ExternAbi;
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use crate::shims::unix::foreign_items::EvalContextExt as _;
use crate::shims::unix::*;
@@ -14,7 +15,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -23,7 +24,7 @@ fn emulate_foreign_item_inner(
// Threading
"pthread_setname_np" => {
let [thread, name] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
// THREAD_NAME_MAX allows a thread name of 31+1 length
// https://github.com/illumos/illumos-gate/blob/7671517e13b8123748eda4ef1ee165c6d9dba7fe/usr/src/uts/common/sys/thread.h#L613
let max_len = 32;
@@ -42,7 +43,7 @@ fn emulate_foreign_item_inner(
}
"pthread_getname_np" => {
let [thread, name, len] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
// See https://illumos.org/man/3C/pthread_getname_np for the error codes.
let res = match this.pthread_getname_np(
this.read_scalar(thread)?,
@@ -60,39 +61,39 @@ fn emulate_foreign_item_inner(
// File related shims
"stat" | "stat64" => {
let [path, buf] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.macos_fbsd_solaris_stat(path, buf)?;
this.write_scalar(result, dest)?;
}
"lstat" | "lstat64" => {
let [path, buf] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.macos_fbsd_solaris_lstat(path, buf)?;
this.write_scalar(result, dest)?;
}
"fstat" | "fstat64" => {
let [fd, buf] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.macos_fbsd_solaris_fstat(fd, buf)?;
this.write_scalar(result, dest)?;
}
"readdir" => {
let [dirp] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.linux_solarish_readdir64("dirent", dirp)?;
this.write_scalar(result, dest)?;
}
// Miscellaneous
"___errno" => {
let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [] = this.check_shim(abi, Conv::C, link_name, args)?;
let errno_place = this.last_error_place()?;
this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
}
"stack_getbounds" => {
let [stack] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let stack = this.deref_pointer_as(stack, this.libc_ty_layout("stack_t"))?;
this.write_int_fields_named(
@@ -111,7 +112,7 @@ fn emulate_foreign_item_inner(
"pset_info" => {
let [pset, tpe, cpus, list] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
// We do not need to handle the current process cpu mask, available_parallelism
// implementation pass null anyway. We only care for the number of
// cpus.
@@ -141,7 +142,7 @@ fn emulate_foreign_item_inner(
"__sysconf_xpg7" => {
let [val] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.sysconf(val)?;
this.write_scalar(result, dest)?;
}
@@ -1,5 +1,6 @@
use rustc_abi::ExternAbi;
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use crate::shims::alloc::EvalContextExt as _;
use crate::*;
@@ -13,7 +14,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -22,13 +23,13 @@ fn emulate_foreign_item_inner(
// Allocation
"posix_memalign" => {
let [memptr, align, size] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.posix_memalign(memptr, align, size)?;
this.write_scalar(result, dest)?;
}
"aligned_alloc" => {
let [align, size] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let res = this.aligned_alloc(align, size)?;
this.write_pointer(res, dest)?;
}
@@ -2,8 +2,10 @@
use std::path::{self, Path, PathBuf};
use std::{io, iter, str};
use rustc_abi::{Align, ExternAbi, Size};
use rustc_abi::{Align, Size};
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use self::shims::windows::handle::{Handle, PseudoHandle};
use crate::shims::os_str::bytes_to_os_str;
@@ -83,12 +85,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_foreign_item_inner(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
let this = self.eval_context_mut();
// According to
// https://github.com/rust-lang/rust/blob/fb00adbdb69266f10df95a4527b767b0ad35ea48/compiler/rustc_target/src/spec/mod.rs#L2766-L2768,
// x86-32 Windows uses a different calling convention than other Windows targets
// for the "system" ABI.
let sys_conv = if this.tcx.sess.target.arch == "x86" { Conv::X86Stdcall } else { Conv::C };
// See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern.
// Windows API stubs.
@@ -101,49 +109,49 @@ fn emulate_foreign_item_inner(
// Environment related shims
"GetEnvironmentVariableW" => {
let [name, buf, size] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let result = this.GetEnvironmentVariableW(name, buf, size)?;
this.write_scalar(result, dest)?;
}
"SetEnvironmentVariableW" => {
let [name, value] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let result = this.SetEnvironmentVariableW(name, value)?;
this.write_scalar(result, dest)?;
}
"GetEnvironmentStringsW" => {
let [] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let result = this.GetEnvironmentStringsW()?;
this.write_pointer(result, dest)?;
}
"FreeEnvironmentStringsW" => {
let [env_block] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let result = this.FreeEnvironmentStringsW(env_block)?;
this.write_scalar(result, dest)?;
}
"GetCurrentDirectoryW" => {
let [size, buf] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let result = this.GetCurrentDirectoryW(size, buf)?;
this.write_scalar(result, dest)?;
}
"SetCurrentDirectoryW" => {
let [path] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let result = this.SetCurrentDirectoryW(path)?;
this.write_scalar(result, dest)?;
}
"GetUserProfileDirectoryW" => {
let [token, buf, size] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let result = this.GetUserProfileDirectoryW(token, buf, size)?;
this.write_scalar(result, dest)?;
}
"GetCurrentProcessId" => {
let [] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let result = this.GetCurrentProcessId()?;
this.write_scalar(result, dest)?;
}
@@ -166,7 +174,7 @@ fn emulate_foreign_item_inner(
n,
byte_offset,
_key,
] = this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
] = this.check_shim(abi, sys_conv, link_name, args)?;
let handle = this.read_target_isize(handle)?;
let buf = this.read_pointer(buf)?;
let n = this.read_scalar(n)?.to_u32()?;
@@ -218,7 +226,7 @@ fn emulate_foreign_item_inner(
}
"GetFullPathNameW" => {
let [filename, size, buffer, filepart] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
this.check_no_isolation("`GetFullPathNameW`")?;
let filename = this.read_pointer(filename)?;
@@ -250,7 +258,7 @@ fn emulate_foreign_item_inner(
// Allocation
"HeapAlloc" => {
let [handle, flags, size] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
this.read_target_isize(handle)?;
let flags = this.read_scalar(flags)?.to_u32()?;
let size = this.read_target_usize(size)?;
@@ -274,7 +282,7 @@ fn emulate_foreign_item_inner(
}
"HeapFree" => {
let [handle, flags, ptr] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
this.read_target_isize(handle)?;
this.read_scalar(flags)?.to_u32()?;
let ptr = this.read_pointer(ptr)?;
@@ -287,7 +295,7 @@ fn emulate_foreign_item_inner(
}
"HeapReAlloc" => {
let [handle, flags, old_ptr, size] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
this.read_target_isize(handle)?;
this.read_scalar(flags)?.to_u32()?;
let old_ptr = this.read_pointer(old_ptr)?;
@@ -307,7 +315,7 @@ fn emulate_foreign_item_inner(
}
"LocalFree" => {
let [ptr] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
// "If the hMem parameter is NULL, LocalFree ignores the parameter and returns NULL."
// (https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localfree)
@@ -320,13 +328,13 @@ fn emulate_foreign_item_inner(
// errno
"SetLastError" => {
let [error] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let error = this.read_scalar(error)?;
this.set_last_error(error)?;
}
"GetLastError" => {
let [] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let last_error = this.get_last_error()?;
this.write_scalar(last_error, dest)?;
}
@@ -335,7 +343,7 @@ fn emulate_foreign_item_inner(
"GetSystemInfo" => {
// Also called from `page_size` crate.
let [system_info] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let system_info =
this.deref_pointer_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?;
// Initialize with `0`.
@@ -359,13 +367,13 @@ fn emulate_foreign_item_inner(
// Create key and return it.
let [] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
}
"TlsGetValue" => {
let [key] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let key = u128::from(this.read_scalar(key)?.to_u32()?);
let active_thread = this.active_thread();
let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
@@ -373,7 +381,7 @@ fn emulate_foreign_item_inner(
}
"TlsSetValue" => {
let [key, new_ptr] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let key = u128::from(this.read_scalar(key)?.to_u32()?);
let active_thread = this.active_thread();
let new_data = this.read_scalar(new_ptr)?;
@@ -383,8 +391,7 @@ fn emulate_foreign_item_inner(
this.write_int(1, dest)?;
}
"TlsFree" => {
let [key] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [key] = this.check_shim(abi, sys_conv, link_name, args)?;
let key = u128::from(this.read_scalar(key)?.to_u32()?);
this.machine.tls.delete_tls_key(key)?;
@@ -395,7 +402,7 @@ fn emulate_foreign_item_inner(
// Access to command-line arguments
"GetCommandLineW" => {
let [] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
this.write_pointer(
this.machine.cmd_line.expect("machine must be initialized"),
dest,
@@ -406,32 +413,32 @@ fn emulate_foreign_item_inner(
"GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => {
#[allow(non_snake_case)]
let [LPFILETIME] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
this.GetSystemTimeAsFileTime(link_name.as_str(), LPFILETIME)?;
}
"QueryPerformanceCounter" => {
#[allow(non_snake_case)]
let [lpPerformanceCount] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let result = this.QueryPerformanceCounter(lpPerformanceCount)?;
this.write_scalar(result, dest)?;
}
"QueryPerformanceFrequency" => {
#[allow(non_snake_case)]
let [lpFrequency] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let result = this.QueryPerformanceFrequency(lpFrequency)?;
this.write_scalar(result, dest)?;
}
"Sleep" => {
let [timeout] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
this.Sleep(timeout)?;
}
"CreateWaitableTimerExW" => {
let [attributes, name, flags, access] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
this.read_pointer(attributes)?;
this.read_pointer(name)?;
this.read_scalar(flags)?.to_u32()?;
@@ -445,30 +452,30 @@ fn emulate_foreign_item_inner(
// Synchronization primitives
"InitOnceBeginInitialize" => {
let [ptr, flags, pending, context] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
this.InitOnceBeginInitialize(ptr, flags, pending, context, dest)?;
}
"InitOnceComplete" => {
let [ptr, flags, context] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let result = this.InitOnceComplete(ptr, flags, context)?;
this.write_scalar(result, dest)?;
}
"WaitOnAddress" => {
let [ptr_op, compare_op, size_op, timeout_op] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?;
}
"WakeByAddressSingle" => {
let [ptr_op] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
this.WakeByAddressSingle(ptr_op)?;
}
"WakeByAddressAll" => {
let [ptr_op] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
this.WakeByAddressAll(ptr_op)?;
}
@@ -477,7 +484,7 @@ fn emulate_foreign_item_inner(
"GetProcAddress" => {
#[allow(non_snake_case)]
let [hModule, lpProcName] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
this.read_target_isize(hModule)?;
let name = this.read_c_str(this.read_pointer(lpProcName)?)?;
if let Ok(name) = str::from_utf8(name)
@@ -493,7 +500,7 @@ fn emulate_foreign_item_inner(
// Threading
"CreateThread" => {
let [security, stacksize, start, arg, flags, thread] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let thread_id =
this.CreateThread(security, stacksize, start, arg, flags, thread)?;
@@ -502,14 +509,14 @@ fn emulate_foreign_item_inner(
}
"WaitForSingleObject" => {
let [handle, timeout] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let ret = this.WaitForSingleObject(handle, timeout)?;
this.write_scalar(ret, dest)?;
}
"GetCurrentThread" => {
let [] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
this.write_scalar(
Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this),
@@ -518,7 +525,7 @@ fn emulate_foreign_item_inner(
}
"SetThreadDescription" => {
let [handle, name] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let handle = this.read_scalar(handle)?;
let name = this.read_wide_str(this.read_pointer(name)?)?;
@@ -543,7 +550,7 @@ fn emulate_foreign_item_inner(
}
"GetThreadDescription" => {
let [handle, name_ptr] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let handle = this.read_scalar(handle)?;
let name_ptr = this.deref_pointer(name_ptr)?; // the pointer where we should store the ptr to the name
@@ -575,7 +582,7 @@ fn emulate_foreign_item_inner(
// Miscellaneous
"ExitProcess" => {
let [code] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let code = this.read_scalar(code)?.to_u32()?;
throw_machine_stop!(TerminationInfo::Exit { code: code.into(), leak_check: false });
}
@@ -583,7 +590,7 @@ fn emulate_foreign_item_inner(
// used by getrandom 0.1
// This is really 'RtlGenRandom'.
let [ptr, len] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let len = this.read_scalar(len)?.to_u32()?;
this.gen_random(ptr, len.into())?;
@@ -592,7 +599,7 @@ fn emulate_foreign_item_inner(
"ProcessPrng" => {
// used by `std`
let [ptr, len] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let ptr = this.read_pointer(ptr)?;
let len = this.read_target_usize(len)?;
this.gen_random(ptr, len)?;
@@ -601,7 +608,7 @@ fn emulate_foreign_item_inner(
"BCryptGenRandom" => {
// used by getrandom 0.2
let [algorithm, ptr, len, flags] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let algorithm = this.read_scalar(algorithm)?;
let algorithm = algorithm.to_target_usize(this)?;
let ptr = this.read_pointer(ptr)?;
@@ -636,7 +643,7 @@ fn emulate_foreign_item_inner(
"GetConsoleScreenBufferInfo" => {
// `term` needs this, so we fake it.
let [console, buffer_info] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
this.read_target_isize(console)?;
// FIXME: this should use deref_pointer_as, but CONSOLE_SCREEN_BUFFER_INFO is not in std
this.deref_pointer(buffer_info)?;
@@ -646,7 +653,7 @@ fn emulate_foreign_item_inner(
}
"GetStdHandle" => {
let [which] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let which = this.read_scalar(which)?.to_i32()?;
// We just make this the identity function, so we know later in `NtWriteFile` which
// one it is. This is very fake, but libtest needs it so we cannot make it a
@@ -656,7 +663,7 @@ fn emulate_foreign_item_inner(
}
"CloseHandle" => {
let [handle] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let ret = this.CloseHandle(handle)?;
@@ -664,7 +671,7 @@ fn emulate_foreign_item_inner(
}
"GetModuleFileNameW" => {
let [handle, filename, size] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
this.check_no_isolation("`GetModuleFileNameW`")?;
let handle = this.read_target_usize(handle)?;
@@ -698,7 +705,7 @@ fn emulate_foreign_item_inner(
}
"FormatMessageW" => {
let [flags, module, message_id, language_id, buffer, size, arguments] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
let flags = this.read_scalar(flags)?.to_u32()?;
let _module = this.read_pointer(module)?; // seems to contain a module name
@@ -734,7 +741,7 @@ fn emulate_foreign_item_inner(
// These shims are enabled only when the caller is in the standard library.
"GetProcessHeap" if this.frame_in_std() => {
let [] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
// Just fake a HANDLE
// It's fine to not use the Handle type here because its a stub
this.write_int(1, dest)?;
@@ -742,20 +749,20 @@ fn emulate_foreign_item_inner(
"GetModuleHandleA" if this.frame_in_std() => {
#[allow(non_snake_case)]
let [_lpModuleName] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
// We need to return something non-null here to make `compat_fn!` work.
this.write_int(1, dest)?;
}
"SetConsoleTextAttribute" if this.frame_in_std() => {
#[allow(non_snake_case)]
let [_hConsoleOutput, _wAttribute] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
// Pretend these does not exist / nothing happened, by returning zero.
this.write_null(dest)?;
}
"GetConsoleMode" if this.frame_in_std() => {
let [console, mode] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
this.read_target_isize(console)?;
this.deref_pointer(mode)?;
// Indicate an error.
@@ -764,28 +771,28 @@ fn emulate_foreign_item_inner(
"GetFileType" if this.frame_in_std() => {
#[allow(non_snake_case)]
let [_hFile] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
// Return unknown file type.
this.write_null(dest)?;
}
"AddVectoredExceptionHandler" if this.frame_in_std() => {
#[allow(non_snake_case)]
let [_First, _Handler] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
// Any non zero value works for the stdlib. This is just used for stack overflows anyway.
this.write_int(1, dest)?;
}
"SetThreadStackGuarantee" if this.frame_in_std() => {
#[allow(non_snake_case)]
let [_StackSizeInBytes] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
// Any non zero value works for the stdlib. This is just used for stack overflows anyway.
this.write_int(1, dest)?;
}
// this is only callable from std because we know that std ignores the return value
"SwitchToThread" if this.frame_in_std() => {
let [] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
this.check_shim(abi, sys_conv, link_name, args)?;
this.yield_active_thread();
@@ -805,7 +812,7 @@ fn emulate_foreign_item_inner(
}
// This function looks and behaves excatly like miri_start_unwind.
let [payload] =
this.check_shim(abi, ExternAbi::C { unwind: true }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
this.handle_miri_start_unwind(payload)?;
return interp_ok(EmulateItemResult::NeedsUnwind);
}
+7 -11
View File
@@ -1,7 +1,7 @@
use rustc_abi::ExternAbi;
use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::LayoutOf as _;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use crate::*;
@@ -10,7 +10,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_x86_aesni_intrinsic(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -27,8 +27,7 @@ fn emulate_x86_aesni_intrinsic(
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdec_si128
"aesdec" | "aesdec.256" | "aesdec.512" => {
let [state, key] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
aes_round(this, state, key, dest, |state, key| {
let key = aes::Block::from(key.to_le_bytes());
let mut state = aes::Block::from(state.to_le_bytes());
@@ -45,7 +44,7 @@ fn emulate_x86_aesni_intrinsic(
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdeclast_si128
"aesdeclast" | "aesdeclast.256" | "aesdeclast.512" => {
let [state, key] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
aes_round(this, state, key, dest, |state, key| {
let mut state = aes::Block::from(state.to_le_bytes());
@@ -70,8 +69,7 @@ fn emulate_x86_aesni_intrinsic(
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenc_si128
"aesenc" | "aesenc.256" | "aesenc.512" => {
let [state, key] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
aes_round(this, state, key, dest, |state, key| {
let key = aes::Block::from(key.to_le_bytes());
let mut state = aes::Block::from(state.to_le_bytes());
@@ -88,8 +86,7 @@ fn emulate_x86_aesni_intrinsic(
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenclast_si128
"aesenclast" | "aesenclast.256" | "aesenclast.512" => {
let [state, key] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
aes_round(this, state, key, dest, |state, key| {
let mut state = aes::Block::from(state.to_le_bytes());
// `aes::hazmat::cipher_round` does the following operations:
@@ -109,8 +106,7 @@ fn emulate_x86_aesni_intrinsic(
// Used to implement the _mm_aesimc_si128 function.
// Performs the AES InvMixColumns operation on `op`
"aesimc" => {
let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
// Transmute to `u128`
let op = op.transmute(this.machine.layouts.u128, this)?;
let dest = dest.transmute(this.machine.layouts.u128, this)?;
+21 -21
View File
@@ -1,9 +1,9 @@
use rustc_abi::ExternAbi;
use rustc_apfloat::ieee::{Double, Single};
use rustc_middle::mir;
use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::LayoutOf as _;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use super::{
FloatBinOp, FloatUnaryOp, bin_op_simd_float_all, conditional_dot_product, convert_float_to_int,
@@ -17,7 +17,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_x86_avx_intrinsic(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -34,7 +34,7 @@ fn emulate_x86_avx_intrinsic(
// semantics.
"min.ps.256" | "max.ps.256" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"min.ps.256" => FloatBinOp::Min,
@@ -47,7 +47,7 @@ fn emulate_x86_avx_intrinsic(
// Used to implement _mm256_min_pd and _mm256_max_pd functions.
"min.pd.256" | "max.pd.256" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"min.pd.256" => FloatBinOp::Min,
@@ -61,7 +61,7 @@ fn emulate_x86_avx_intrinsic(
// Rounds the elements of `op` according to `rounding`.
"round.ps.256" => {
let [op, rounding] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
round_all::<rustc_apfloat::ieee::Single>(this, op, rounding, dest)?;
}
@@ -69,14 +69,14 @@ fn emulate_x86_avx_intrinsic(
// Rounds the elements of `op` according to `rounding`.
"round.pd.256" => {
let [op, rounding] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
round_all::<rustc_apfloat::ieee::Double>(this, op, rounding, dest)?;
}
// Used to implement _mm256_{rcp,rsqrt}_ps functions.
// Performs the operations on all components of `op`.
"rcp.ps.256" | "rsqrt.ps.256" => {
let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"rcp.ps.256" => FloatUnaryOp::Rcp,
@@ -89,7 +89,7 @@ fn emulate_x86_avx_intrinsic(
// Used to implement the _mm256_dp_ps function.
"dp.ps.256" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
conditional_dot_product(this, left, right, imm, dest)?;
}
@@ -98,7 +98,7 @@ fn emulate_x86_avx_intrinsic(
// in `left` and `right`.
"hadd.ps.256" | "hadd.pd.256" | "hsub.ps.256" | "hsub.pd.256" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"hadd.ps.256" | "hadd.pd.256" => mir::BinOp::Add,
@@ -114,7 +114,7 @@ fn emulate_x86_avx_intrinsic(
// if true.
"cmp.ps.256" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -127,7 +127,7 @@ fn emulate_x86_avx_intrinsic(
// if true.
"cmp.pd.256" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -138,7 +138,7 @@ fn emulate_x86_avx_intrinsic(
// and _mm256_cvttpd_epi32 functions.
// Converts packed f32/f64 to packed i32.
"cvt.ps2dq.256" | "cvtt.ps2dq.256" | "cvt.pd2dq.256" | "cvtt.pd2dq.256" => {
let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
let rnd = match unprefixed_name {
// "current SSE rounding mode", assume nearest
@@ -157,7 +157,7 @@ fn emulate_x86_avx_intrinsic(
// `control` determines which element of the current `data` array is written.
"vpermilvar.ps" | "vpermilvar.ps.256" => {
let [data, control] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (data, data_len) = this.project_to_simd(data)?;
let (control, control_len) = this.project_to_simd(control)?;
@@ -191,7 +191,7 @@ fn emulate_x86_avx_intrinsic(
// written.
"vpermilvar.pd" | "vpermilvar.pd.256" => {
let [data, control] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (data, data_len) = this.project_to_simd(data)?;
let (control, control_len) = this.project_to_simd(control)?;
@@ -224,7 +224,7 @@ fn emulate_x86_avx_intrinsic(
// zero, according to `imm`.
"vperm2f128.ps.256" | "vperm2f128.pd.256" | "vperm2f128.si.256" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
assert_eq!(dest.layout, left.layout);
assert_eq!(dest.layout, right.layout);
@@ -268,7 +268,7 @@ fn emulate_x86_avx_intrinsic(
// loaded.
"maskload.ps" | "maskload.pd" | "maskload.ps.256" | "maskload.pd.256" => {
let [ptr, mask] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
mask_load(this, ptr, mask, dest)?;
}
@@ -279,7 +279,7 @@ fn emulate_x86_avx_intrinsic(
// Unlike SSE2's _mm_maskmoveu_si128, these are not non-temporal stores.
"maskstore.ps" | "maskstore.pd" | "maskstore.ps.256" | "maskstore.pd.256" => {
let [ptr, mask, value] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
mask_store(this, ptr, mask, value)?;
}
@@ -290,7 +290,7 @@ fn emulate_x86_avx_intrinsic(
// unaligned read.
"ldu.dq.256" => {
let [src_ptr] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let src_ptr = this.read_pointer(src_ptr)?;
let dest = dest.force_mplace(this)?;
@@ -303,7 +303,7 @@ fn emulate_x86_avx_intrinsic(
// `op & mask != 0 && op & mask != mask`
"ptestz.256" | "ptestc.256" | "ptestnzc.256" => {
let [op, mask] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (all_zero, masked_set) = test_bits_masked(this, op, mask)?;
let res = match unprefixed_name {
@@ -327,7 +327,7 @@ fn emulate_x86_avx_intrinsic(
| "vtestnzc.pd" | "vtestz.ps.256" | "vtestc.ps.256" | "vtestnzc.ps.256"
| "vtestz.ps" | "vtestc.ps" | "vtestnzc.ps" => {
let [op, mask] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (direct, negated) = test_high_bits_masked(this, op, mask)?;
let res = match unprefixed_name {
@@ -349,7 +349,7 @@ fn emulate_x86_avx_intrinsic(
// compiler, making these functions no-ops.
// The only thing that needs to be ensured is the correct calling convention.
let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [] = this.check_shim(abi, Conv::C, link_name, args)?;
}
_ => return interp_ok(EmulateItemResult::NotSupported),
}
+22 -22
View File
@@ -1,8 +1,8 @@
use rustc_abi::ExternAbi;
use rustc_middle::mir;
use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::LayoutOf as _;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use super::{
ShiftOp, horizontal_bin_op, int_abs, mask_load, mask_store, mpsadbw, packssdw, packsswb,
@@ -15,7 +15,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_x86_avx2_intrinsic(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -28,7 +28,7 @@ fn emulate_x86_avx2_intrinsic(
// Used to implement the _mm256_abs_epi{8,16,32} functions.
// Calculates the absolute value of packed 8/16/32-bit integers.
"pabs.b" | "pabs.w" | "pabs.d" => {
let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
int_abs(this, op, dest)?;
}
@@ -37,7 +37,7 @@ fn emulate_x86_avx2_intrinsic(
// integer values in `left` and `right`.
"phadd.w" | "phadd.sw" | "phadd.d" | "phsub.w" | "phsub.sw" | "phsub.d" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (which, saturating) = match unprefixed_name {
"phadd.w" | "phadd.d" => (mir::BinOp::Add, false),
@@ -58,7 +58,7 @@ fn emulate_x86_avx2_intrinsic(
| "gather.d.pd.256" | "gather.q.pd" | "gather.q.pd.256" | "gather.d.ps"
| "gather.d.ps.256" | "gather.q.ps" | "gather.q.ps.256" => {
let [src, slice, offsets, mask, scale] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
assert_eq!(dest.layout, src.layout);
@@ -116,7 +116,7 @@ fn emulate_x86_avx2_intrinsic(
// intermediate 32-bit integers, and pack the results in `dest`.
"pmadd.wd" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -153,7 +153,7 @@ fn emulate_x86_avx2_intrinsic(
// produces the output at index `i`.
"pmadd.ub.sw" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -188,7 +188,7 @@ fn emulate_x86_avx2_intrinsic(
// loaded.
"maskload.d" | "maskload.q" | "maskload.d.256" | "maskload.q.256" => {
let [ptr, mask] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
mask_load(this, ptr, mask, dest)?;
}
@@ -199,7 +199,7 @@ fn emulate_x86_avx2_intrinsic(
// Unlike SSE2's _mm_maskmoveu_si128, these are not non-temporal stores.
"maskstore.d" | "maskstore.q" | "maskstore.d.256" | "maskstore.q.256" => {
let [ptr, mask, value] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
mask_store(this, ptr, mask, value)?;
}
@@ -211,7 +211,7 @@ fn emulate_x86_avx2_intrinsic(
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mpsadbw_epu8
"mpsadbw" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
mpsadbw(this, left, right, imm, dest)?;
}
@@ -223,7 +223,7 @@ fn emulate_x86_avx2_intrinsic(
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mulhrs_epi16
"pmul.hr.sw" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
pmulhrsw(this, left, right, dest)?;
}
@@ -232,7 +232,7 @@ fn emulate_x86_avx2_intrinsic(
// vector with signed saturation.
"packsswb" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
packsswb(this, left, right, dest)?;
}
@@ -241,7 +241,7 @@ fn emulate_x86_avx2_intrinsic(
// vector with signed saturation.
"packssdw" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
packssdw(this, left, right, dest)?;
}
@@ -250,7 +250,7 @@ fn emulate_x86_avx2_intrinsic(
// unsigned integer vector with saturation.
"packuswb" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
packuswb(this, left, right, dest)?;
}
@@ -259,7 +259,7 @@ fn emulate_x86_avx2_intrinsic(
// the result to a 16-bit unsigned integer vector with saturation.
"packusdw" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
packusdw(this, left, right, dest)?;
}
@@ -269,7 +269,7 @@ fn emulate_x86_avx2_intrinsic(
// as indices.
"permd" | "permps" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -290,7 +290,7 @@ fn emulate_x86_avx2_intrinsic(
// Shuffles 128-bit blocks of `a` and `b` using `imm` as pattern.
"vperm2i128" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
assert_eq!(left.layout.size.bits(), 256);
assert_eq!(right.layout.size.bits(), 256);
@@ -328,7 +328,7 @@ fn emulate_x86_avx2_intrinsic(
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_sad_epu8
"psad.bw" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -361,7 +361,7 @@ fn emulate_x86_avx2_intrinsic(
// Each 128-bit block is shuffled independently.
"pshuf.b" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -393,7 +393,7 @@ fn emulate_x86_avx2_intrinsic(
// Basically, we multiply `left` with `right.signum()`.
"psign.b" | "psign.w" | "psign.d" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
psign(this, left, right, dest)?;
}
@@ -408,7 +408,7 @@ fn emulate_x86_avx2_intrinsic(
"psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q"
| "psrl.q" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"psll.w" | "psll.d" | "psll.q" => ShiftOp::Left,
@@ -424,7 +424,7 @@ fn emulate_x86_avx2_intrinsic(
"psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" | "psrlv.d" | "psrlv.d.256"
| "psrlv.q" | "psrlv.q.256" | "psrav.d" | "psrav.d.256" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" => ShiftOp::Left,
+4 -3
View File
@@ -1,5 +1,6 @@
use rustc_abi::ExternAbi;
use rustc_span::Symbol;
use rustc_middle::ty::Ty;
use rustc_target::callconv::{Conv, FnAbi};
use crate::*;
@@ -8,7 +9,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_x86_bmi_intrinsic(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -34,7 +35,7 @@ fn emulate_x86_bmi_intrinsic(
}
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let left = this.read_scalar(left)?;
let right = this.read_scalar(right)?;
+6 -6
View File
@@ -1,5 +1,6 @@
use rustc_abi::ExternAbi;
use rustc_span::Symbol;
use rustc_middle::ty::Ty;
use rustc_target::callconv::{Conv, FnAbi};
use crate::*;
@@ -8,7 +9,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_x86_gfni_intrinsic(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -30,7 +31,7 @@ fn emulate_x86_gfni_intrinsic(
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8affine_
"vgf2p8affineqb.128" | "vgf2p8affineqb.256" | "vgf2p8affineqb.512" => {
let [left, right, imm8] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
affine_transform(this, left, right, imm8, dest, /* inverse */ false)?;
}
// Used to implement the `_mm{, 256, 512}_gf2p8affineinv_epi64_epi8` functions.
@@ -38,7 +39,7 @@ fn emulate_x86_gfni_intrinsic(
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8affineinv
"vgf2p8affineinvqb.128" | "vgf2p8affineinvqb.256" | "vgf2p8affineinvqb.512" => {
let [left, right, imm8] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
affine_transform(this, left, right, imm8, dest, /* inverse */ true)?;
}
// Used to implement the `_mm{, 256, 512}_gf2p8mul_epi8` functions.
@@ -48,8 +49,7 @@ fn emulate_x86_gfni_intrinsic(
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=gf2p8mul
"vgf2p8mulb.128" | "vgf2p8mulb.256" | "vgf2p8mulb.512" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
let (dest, dest_len) = this.project_to_simd(dest)?;
+7 -8
View File
@@ -1,10 +1,11 @@
use rustc_abi::{ExternAbi, Size};
use rustc_abi::Size;
use rustc_apfloat::Float;
use rustc_apfloat::ieee::Single;
use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::LayoutOf as _;
use rustc_middle::{mir, ty};
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use self::helpers::bool_to_simd_element;
use crate::*;
@@ -27,7 +28,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_x86_intrinsic(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -45,8 +46,7 @@ fn emulate_x86_intrinsic(
return interp_ok(EmulateItemResult::NotSupported);
}
let [cb_in, a, b] = this.check_shim(abi, ExternAbi::Unadjusted, link_name, args)?;
let [cb_in, a, b] = this.check_shim(abi, Conv::C, link_name, args)?;
let op = if unprefixed_name.starts_with("add") {
mir::BinOp::AddWithOverflow
} else {
@@ -68,9 +68,8 @@ fn emulate_x86_intrinsic(
if is_u64 && this.tcx.sess.target.arch != "x86_64" {
return interp_ok(EmulateItemResult::NotSupported);
}
let [c_in, a, b, out] =
this.check_shim(abi, ExternAbi::Unadjusted, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let out = this.deref_pointer_as(
out,
if is_u64 { this.machine.layouts.u64 } else { this.machine.layouts.u32 },
@@ -87,7 +86,7 @@ fn emulate_x86_intrinsic(
// the instruction behaves like a no-op, so it is always safe to call the
// intrinsic.
"sse2.pause" => {
let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [] = this.check_shim(abi, Conv::C, link_name, args)?;
// Only exhibit the spin-loop hint behavior when SSE2 is enabled.
if this.tcx.sess.unstable_target_features.contains(&Symbol::intern("sse2")) {
this.yield_active_thread();
@@ -107,7 +106,7 @@ fn emulate_x86_intrinsic(
}
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
pclmulqdq(this, left, right, imm, dest, len)?;
}
+6 -5
View File
@@ -4,8 +4,9 @@
//!
//! [RustCrypto's sha256 module]: https://github.com/RustCrypto/hashes/blob/6be8466247e936c415d8aafb848697f39894a386/sha2/src/sha256/soft.rs
use rustc_abi::ExternAbi;
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use crate::*;
@@ -14,7 +15,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_x86_sha_intrinsic(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -52,7 +53,7 @@ fn write<'c>(
// Used to implement the _mm_sha256rnds2_epu32 function.
"256rnds2" => {
let [a, b, k] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (a_reg, a_len) = this.project_to_simd(a)?;
let (b_reg, b_len) = this.project_to_simd(b)?;
@@ -74,7 +75,7 @@ fn write<'c>(
// Used to implement the _mm_sha256msg1_epu32 function.
"256msg1" => {
let [a, b] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (a_reg, a_len) = this.project_to_simd(a)?;
let (b_reg, b_len) = this.project_to_simd(b)?;
@@ -93,7 +94,7 @@ fn write<'c>(
// Used to implement the _mm_sha256msg2_epu32 function.
"256msg2" => {
let [a, b] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (a_reg, a_len) = this.project_to_simd(a)?;
let (b_reg, b_len) = this.project_to_simd(b)?;
+12 -11
View File
@@ -1,6 +1,7 @@
use rustc_abi::ExternAbi;
use rustc_apfloat::ieee::Single;
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use super::{
FloatBinOp, FloatUnaryOp, bin_op_simd_float_all, bin_op_simd_float_first, unary_op_ps,
@@ -13,7 +14,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_x86_sse_intrinsic(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -33,7 +34,7 @@ fn emulate_x86_sse_intrinsic(
// `right` and copies the remaining components from `left`.
"min.ss" | "max.ss" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"min.ss" => FloatBinOp::Min,
@@ -50,7 +51,7 @@ fn emulate_x86_sse_intrinsic(
// semantics.
"min.ps" | "max.ps" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"min.ps" => FloatBinOp::Min,
@@ -64,7 +65,7 @@ fn emulate_x86_sse_intrinsic(
// Performs the operations on the first component of `op` and
// copies the remaining components from `op`.
"rcp.ss" | "rsqrt.ss" => {
let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"rcp.ss" => FloatUnaryOp::Rcp,
@@ -77,7 +78,7 @@ fn emulate_x86_sse_intrinsic(
// Used to implement _mm_{sqrt,rcp,rsqrt}_ps functions.
// Performs the operations on all components of `op`.
"rcp.ps" | "rsqrt.ps" => {
let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"rcp.ps" => FloatUnaryOp::Rcp,
@@ -97,7 +98,7 @@ fn emulate_x86_sse_intrinsic(
// with hard-coded operations.
"cmp.ss" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -114,7 +115,7 @@ fn emulate_x86_sse_intrinsic(
// with hard-coded operations.
"cmp.ps" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -128,7 +129,7 @@ fn emulate_x86_sse_intrinsic(
| "ucomieq.ss" | "ucomilt.ss" | "ucomile.ss" | "ucomigt.ss" | "ucomige.ss"
| "ucomineq.ss" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -156,7 +157,7 @@ fn emulate_x86_sse_intrinsic(
// _mm_cvtss_si64 and _mm_cvttss_si64 functions.
// Converts the first component of `op` from f32 to i32/i64.
"cvtss2si" | "cvttss2si" | "cvtss2si64" | "cvttss2si64" => {
let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
let (op, _) = this.project_to_simd(op)?;
let op = this.read_immediate(&this.project_index(&op, 0)?)?;
@@ -185,7 +186,7 @@ fn emulate_x86_sse_intrinsic(
// https://www.felixcloutier.com/x86/cvtsi2ss
"cvtsi2ss" | "cvtsi642ss" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (dest, dest_len) = this.project_to_simd(dest)?;
+17 -16
View File
@@ -1,6 +1,7 @@
use rustc_abi::ExternAbi;
use rustc_apfloat::ieee::Double;
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use super::{
FloatBinOp, ShiftOp, bin_op_simd_float_all, bin_op_simd_float_first, convert_float_to_int,
@@ -13,7 +14,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_x86_sse2_intrinsic(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -40,7 +41,7 @@ fn emulate_x86_sse2_intrinsic(
// intermediate 32-bit integers, and pack the results in `dest`.
"pmadd.wd" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -79,7 +80,7 @@ fn emulate_x86_sse2_intrinsic(
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sad_epu8
"psad.bw" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -118,7 +119,7 @@ fn emulate_x86_sse2_intrinsic(
"psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q"
| "psrl.q" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"psll.w" | "psll.d" | "psll.q" => ShiftOp::Left,
@@ -133,7 +134,7 @@ fn emulate_x86_sse2_intrinsic(
// and _mm_cvttpd_epi32 functions.
// Converts packed f32/f64 to packed i32.
"cvtps2dq" | "cvttps2dq" | "cvtpd2dq" | "cvttpd2dq" => {
let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
let (op_len, _) = op.layout.ty.simd_size_and_type(*this.tcx);
let (dest_len, _) = dest.layout.ty.simd_size_and_type(*this.tcx);
@@ -171,7 +172,7 @@ fn emulate_x86_sse2_intrinsic(
// vector with signed saturation.
"packsswb.128" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
packsswb(this, left, right, dest)?;
}
@@ -180,7 +181,7 @@ fn emulate_x86_sse2_intrinsic(
// unsigned integer vector with saturation.
"packuswb.128" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
packuswb(this, left, right, dest)?;
}
@@ -189,7 +190,7 @@ fn emulate_x86_sse2_intrinsic(
// vector with signed saturation.
"packssdw.128" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
packssdw(this, left, right, dest)?;
}
@@ -200,7 +201,7 @@ fn emulate_x86_sse2_intrinsic(
// semantics.
"min.sd" | "max.sd" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"min.sd" => FloatBinOp::Min,
@@ -217,7 +218,7 @@ fn emulate_x86_sse2_intrinsic(
// semantics.
"min.pd" | "max.pd" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"min.pd" => FloatBinOp::Min,
@@ -237,7 +238,7 @@ fn emulate_x86_sse2_intrinsic(
// with hard-coded operations.
"cmp.sd" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -254,7 +255,7 @@ fn emulate_x86_sse2_intrinsic(
// with hard-coded operations.
"cmp.pd" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@@ -268,7 +269,7 @@ fn emulate_x86_sse2_intrinsic(
| "ucomieq.sd" | "ucomilt.sd" | "ucomile.sd" | "ucomigt.sd" | "ucomige.sd"
| "ucomineq.sd" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -296,7 +297,7 @@ fn emulate_x86_sse2_intrinsic(
// _mm_cvtsd_si64 and _mm_cvttsd_si64 functions.
// Converts the first component of `op` from f64 to i32/i64.
"cvtsd2si" | "cvttsd2si" | "cvtsd2si64" | "cvttsd2si64" => {
let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
let (op, _) = this.project_to_simd(op)?;
let op = this.read_immediate(&this.project_index(&op, 0)?)?;
@@ -323,7 +324,7 @@ fn emulate_x86_sse2_intrinsic(
// the remaining elements from `left`
"cvtsd2ss" | "cvtss2sd" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, _) = this.project_to_simd(right)?;
+5 -4
View File
@@ -1,6 +1,7 @@
use rustc_abi::ExternAbi;
use rustc_middle::mir;
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use super::horizontal_bin_op;
use crate::*;
@@ -10,7 +11,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_x86_sse3_intrinsic(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -25,7 +26,7 @@ fn emulate_x86_sse3_intrinsic(
// in `left` and `right`.
"hadd.ps" | "hadd.pd" | "hsub.ps" | "hsub.pd" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"hadd.ps" | "hadd.pd" => mir::BinOp::Add,
@@ -42,7 +43,7 @@ fn emulate_x86_sse3_intrinsic(
// unaligned read.
"ldu.dq" => {
let [src_ptr] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let src_ptr = this.read_pointer(src_ptr)?;
let dest = dest.force_mplace(this)?;
+13 -12
View File
@@ -1,5 +1,6 @@
use rustc_abi::ExternAbi;
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use super::{conditional_dot_product, mpsadbw, packusdw, round_all, round_first, test_bits_masked};
use crate::*;
@@ -9,7 +10,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_x86_sse41_intrinsic(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -27,7 +28,7 @@ fn emulate_x86_sse41_intrinsic(
// `i` is zeroed.
"insertps" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -63,7 +64,7 @@ fn emulate_x86_sse41_intrinsic(
// the result to a 16-bit unsigned integer vector with saturation.
"packusdw" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
packusdw(this, left, right, dest)?;
}
@@ -74,7 +75,7 @@ fn emulate_x86_sse41_intrinsic(
// 4 bits of `imm`.
"dpps" | "dppd" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
conditional_dot_product(this, left, right, imm, dest)?;
}
@@ -83,7 +84,7 @@ fn emulate_x86_sse41_intrinsic(
// and copies the remaining elements from `left`.
"round.ss" => {
let [left, right, rounding] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
round_first::<rustc_apfloat::ieee::Single>(this, left, right, rounding, dest)?;
}
@@ -91,7 +92,7 @@ fn emulate_x86_sse41_intrinsic(
// functions. Rounds the elements of `op` according to `rounding`.
"round.ps" => {
let [op, rounding] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
round_all::<rustc_apfloat::ieee::Single>(this, op, rounding, dest)?;
}
@@ -100,7 +101,7 @@ fn emulate_x86_sse41_intrinsic(
// and copies the remaining elements from `left`.
"round.sd" => {
let [left, right, rounding] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
round_first::<rustc_apfloat::ieee::Double>(this, left, right, rounding, dest)?;
}
@@ -108,7 +109,7 @@ fn emulate_x86_sse41_intrinsic(
// functions. Rounds the elements of `op` according to `rounding`.
"round.pd" => {
let [op, rounding] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
round_all::<rustc_apfloat::ieee::Double>(this, op, rounding, dest)?;
}
@@ -116,7 +117,7 @@ fn emulate_x86_sse41_intrinsic(
// Find the minimum unsinged 16-bit integer in `op` and
// returns its value and position.
"phminposuw" => {
let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
let (op, op_len) = this.project_to_simd(op)?;
let (dest, dest_len) = this.project_to_simd(dest)?;
@@ -151,7 +152,7 @@ fn emulate_x86_sse41_intrinsic(
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mpsadbw_epu8
"mpsadbw" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
mpsadbw(this, left, right, imm, dest)?;
}
@@ -161,7 +162,7 @@ fn emulate_x86_sse41_intrinsic(
// `(op & mask) != 0 && (op & mask) != mask`
"ptestz" | "ptestc" | "ptestnzc" => {
let [op, mask] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (all_zero, masked_set) = test_bits_masked(this, op, mask)?;
let res = match unprefixed_name {
+9 -8
View File
@@ -1,8 +1,9 @@
use rustc_abi::{ExternAbi, Size};
use rustc_abi::Size;
use rustc_middle::mir;
use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::LayoutOf as _;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use crate::*;
@@ -200,7 +201,7 @@ fn deconstruct_args<'tcx>(
unprefixed_name: &str,
ecx: &mut MiriInterpCx<'tcx>,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
) -> InterpResult<'tcx, (OpTy<'tcx>, OpTy<'tcx>, Option<(u64, u64)>, u8)> {
let array_layout_fn = |ecx: &mut MiriInterpCx<'tcx>, imm: u8| {
@@ -223,7 +224,7 @@ fn deconstruct_args<'tcx>(
if is_explicit {
let [str1, len1, str2, len2, imm] =
ecx.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
ecx.check_shim(abi, Conv::C, link_name, args)?;
let imm = ecx.read_scalar(imm)?.to_u8()?;
let default_len = default_len::<u32>(imm);
@@ -237,7 +238,7 @@ fn deconstruct_args<'tcx>(
interp_ok((str1, str2, Some((len1, len2)), imm))
} else {
let [str1, str2, imm] =
ecx.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
ecx.check_shim(abi, Conv::C, link_name, args)?;
let imm = ecx.read_scalar(imm)?.to_u8()?;
let array_layout = array_layout_fn(ecx, imm)?;
@@ -279,7 +280,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_x86_sse42_intrinsic(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -388,7 +389,7 @@ fn emulate_x86_sse42_intrinsic(
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ig_expand=924,925
"pcmpistriz128" | "pcmpistris128" => {
let [str1, str2, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let imm = this.read_scalar(imm)?.to_u8()?;
let str = if unprefixed_name == "pcmpistris128" { str1 } else { str2 };
@@ -409,7 +410,7 @@ fn emulate_x86_sse42_intrinsic(
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ig_expand=1046,1047
"pcmpestriz128" | "pcmpestris128" => {
let [_, len1, _, len2, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let len = if unprefixed_name == "pcmpestris128" { len1 } else { len2 };
let len = this.read_scalar(len)?.to_i32()?;
let imm = this.read_scalar(imm)?.to_u8()?;
@@ -437,7 +438,7 @@ fn emulate_x86_sse42_intrinsic(
}
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let left = this.read_scalar(left)?;
let right = this.read_scalar(right)?;
+9 -8
View File
@@ -1,6 +1,7 @@
use rustc_abi::ExternAbi;
use rustc_middle::mir;
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use super::{horizontal_bin_op, int_abs, pmulhrsw, psign};
use crate::*;
@@ -10,7 +11,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn emulate_x86_ssse3_intrinsic(
&mut self,
link_name: Symbol,
abi: ExternAbi,
abi: &FnAbi<'tcx, Ty<'tcx>>,
args: &[OpTy<'tcx>],
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx, EmulateItemResult> {
@@ -23,7 +24,7 @@ fn emulate_x86_ssse3_intrinsic(
// Used to implement the _mm_abs_epi{8,16,32} functions.
// Calculates the absolute value of packed 8/16/32-bit integers.
"pabs.b.128" | "pabs.w.128" | "pabs.d.128" => {
let [op] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [op] = this.check_shim(abi, Conv::C, link_name, args)?;
int_abs(this, op, dest)?;
}
@@ -32,7 +33,7 @@ fn emulate_x86_ssse3_intrinsic(
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_shuffle_epi8
"pshuf.b.128" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -62,7 +63,7 @@ fn emulate_x86_ssse3_intrinsic(
"phadd.w.128" | "phadd.sw.128" | "phadd.d.128" | "phsub.w.128" | "phsub.sw.128"
| "phsub.d.128" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (which, saturating) = match unprefixed_name {
"phadd.w.128" | "phadd.d.128" => (mir::BinOp::Add, false),
@@ -82,7 +83,7 @@ fn emulate_x86_ssse3_intrinsic(
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_maddubs_epi16
"pmadd.ub.sw.128" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
let (left, left_len) = this.project_to_simd(left)?;
let (right, right_len) = this.project_to_simd(right)?;
@@ -118,7 +119,7 @@ fn emulate_x86_ssse3_intrinsic(
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mulhrs_epi16
"pmul.hr.sw.128" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
pmulhrsw(this, left, right, dest)?;
}
@@ -129,7 +130,7 @@ fn emulate_x86_ssse3_intrinsic(
// Basically, we multiply `left` with `right.signum()`.
"psign.b.128" | "psign.w.128" | "psign.d.128" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
this.check_shim(abi, Conv::C, link_name, args)?;
psign(this, left, right, dest)?;
}
@@ -189,6 +189,10 @@ Options:
--include-parts-dir path/to/doc.parts/<crate-name>
Includes trait implementations and other crate info
from provided path. Only use with --merge=finalize
--html-no-source
Disable HTML source code pages generation
--doctest-compilation-args add arguments to be used when compiling doctests
--disable-minification
removed
--plugin-path DIR
@@ -209,8 +213,6 @@ Options:
removed, see issue #44136
<https://github.com/rust-lang/rust/issues/44136> for
more information
--html-no-source
Disable HTML source code pages generation
@path Read newline separated options from `path`
@@ -0,0 +1,17 @@
// This test checks that the test behave when `--doctest-compilation-args` is passed
// multiple times.
//@ check-pass
//@ compile-flags: --test -Zunstable-options --doctest-compilation-args=--cfg=testcase_must_be_present
//@ compile-flags: --doctest-compilation-args=--cfg=another
//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME"
/// ```
/// #[cfg(testcase_must_be_present)]
/// #[cfg(another)]
/// fn must_be_present() {}
///
/// fn main() { must_be_present() }
/// ```
pub struct Bar;
@@ -0,0 +1,6 @@
running 1 test
test $DIR/rustflags-multiple-args.rs - Bar (line 10) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+12
View File
@@ -0,0 +1,12 @@
//@ check-pass
//@ compile-flags: --test -Zunstable-options --doctest-compilation-args=--cfg=testcase_must_be_present
//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME"
/// ```
/// #[cfg(testcase_must_be_present)]
/// fn must_be_present() {}
///
/// fn main() { must_be_present() }
/// ```
pub struct Bar;
@@ -0,0 +1,6 @@
running 1 test
test $DIR/rustflags.rs - Bar (line 6) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+30
View File
@@ -0,0 +1,30 @@
pub struct Struct {
_private: (),
}
pub trait Trait {
//@ has assoc_consts_underscore/trait.Trait.html '//pre[@class="rust item-decl"]' \
// 'const REQUIRED: Struct;'
//@ !has - '//*[@id="associatedconstant.REQUIRED"]' 'const REQUIRED: Struct = _'
//@ has - '//*[@id="associatedconstant.REQUIRED"]' 'const REQUIRED: Struct'
const REQUIRED: Struct;
//@ has - '//pre[@class="rust item-decl"]' 'const OPTIONAL: Struct = _;'
//@ has - '//*[@id="associatedconstant.OPTIONAL"]' 'const OPTIONAL: Struct = _'
const OPTIONAL: Struct = Struct { _private: () };
}
impl Trait for Struct {
//@ !has assoc_consts_underscore/struct.Struct.html '//*[@id="associatedconstant.REQUIRED"]' \
// 'const REQUIRED: Struct = _'
//@ has - '//*[@id="associatedconstant.REQUIRED"]' 'const REQUIRED: Struct'
const REQUIRED: Struct = Struct { _private: () };
//@ !has - '//*[@id="associatedconstant.OPTIONAL"]' 'const OPTIONAL: Struct = _'
//@ has - '//*[@id="associatedconstant.OPTIONAL"]' 'const OPTIONAL: Struct'
const OPTIONAL: Struct = Struct { _private: () };
}
impl Struct {
//@ !has - '//*[@id="associatedconstant.INHERENT"]' 'const INHERENT: Struct = _'
//@ has - '//*[@id="associatedconstant.INHERENT"]' 'const INHERENT: Struct'
pub const INHERENT: Struct = Struct { _private: () };
}
+1 -1
View File
@@ -14,6 +14,6 @@ impl<const B: Word> Repr<B> {
// If we change back to rendering the value of consts, check this doesn't add
// a <b> tag, but escapes correctly
//@ has foo/struct.Repr.html '//section[@id="associatedconstant.BASE"]/h4' '= _'
//@ !has foo/struct.Repr.html '//section[@id="associatedconstant.BASE"]/h4' '='
pub const BASE: IBig = base_as_ibig::<B>();
}