Merge pull request #4101 from RalfJung/rustup

Rustup
This commit is contained in:
Ralf Jung 2024-12-20 10:55:11 +00:00 committed by GitHub
commit fddff471f6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
64 changed files with 947 additions and 809 deletions

View file

@ -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 @@ where
}
#[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 @@ where
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()),
}
}

View file

@ -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 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine {
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>,

View file

@ -2,7 +2,7 @@ use std::borrow::{Borrow, Cow};
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::layout::{HasTypingEnv, TyAndLayout};
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 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
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>,

View file

@ -519,7 +519,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
return M::call_extra_fn(
self,
extra,
caller_abi,
caller_fn_abi,
args,
destination,
target,
@ -570,7 +570,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let Some((body, instance)) = M::find_mir_or_eval_fn(
self,
instance,
caller_abi,
caller_fn_abi,
args,
destination,
target,

View file

@ -6,7 +6,7 @@ use std::borrow::{Borrow, Cow};
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::ty::layout::TyAndLayout;
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 @@ pub trait Machine<'tcx>: Sized {
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 @@ pub trait Machine<'tcx>: Sized {
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 @@ pub macro compile_time_machine(<$tcx: lifetime>) {
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>,

View file

@ -1229,23 +1229,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
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));
}
}
}
}

View file

@ -1191,6 +1191,14 @@ impl<T: Idx> MixedBitSet<T> {
}
}
#[inline]
pub fn clear(&mut self) {
match self {
MixedBitSet::Small(set) => set.clear(),
MixedBitSet::Large(set) => set.clear(),
}
}
bit_relations_inherent_impls! {}
}

View file

@ -1824,7 +1824,10 @@ impl<T, A: Allocator> Vec<T, 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 @@ impl<T, A: Allocator> Vec<T, 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) {

View file

@ -527,7 +527,7 @@ impl Ipv4Addr {
/// ```
/// 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 @@ impl Ipv6Addr {
/// 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 @@ impl Ipv6Addr {
/// ```
/// 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,

View file

@ -4641,7 +4641,7 @@ impl<T> [T] {
/// 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 @@ impl<T> [T] {
/// 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 @@ impl<T> [T] {
/// 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 @@ impl<T> [T] {
/// 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

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?",
]
```

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 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
bounds,
)
} else {
TyAssocTypeItem(generics, bounds)
RequiredAssocTypeItem(generics, bounds)
}
} else {
AssocTypeItem(

View file

@ -545,14 +545,14 @@ impl Item {
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 @@ impl Item {
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 @@ impl Item {
// 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 @@ impl ItemKind {
| StaticItem(_)
| ConstantItem(_)
| TraitAliasItem(_)
| TyMethodItem(_)
| RequiredMethodItem(_)
| MethodItem(_, _)
| StructFieldItem(_)
| ForeignFunctionItem(_, _)
@ -909,9 +918,10 @@ impl ItemKind {
| MacroItem(_)
| ProcMacroItem(_)
| PrimitiveItem(_)
| TyAssocConstItem(..)
| AssocConstItem(..)
| TyAssocTypeItem(..)
| RequiredAssocConstItem(..)
| ProvidedAssocConstItem(..)
| ImplAssocConstItem(..)
| RequiredAssocTypeItem(..)
| AssocTypeItem(..)
| StrippedItem(_)
| KeywordItem => [].iter(),

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 @@ impl Options {
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 @@ impl Options {
scrape_examples_options,
unstable_features,
expanded_args: args,
doctest_compilation_args,
};
let render_options = RenderOptions {
output,

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())

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"]);
}

View file

@ -82,7 +82,7 @@ pub(crate) trait DocFolder: Sized {
| StaticItem(_)
| ConstantItem(..)
| TraitAliasItem(_)
| TyMethodItem(_)
| RequiredMethodItem(_)
| MethodItem(_, _)
| StructFieldItem(_)
| ForeignFunctionItem(..)
@ -91,9 +91,10 @@ pub(crate) trait DocFolder: Sized {
| MacroItem(_)
| ProcMacroItem(_)
| PrimitiveItem(_)
| TyAssocConstItem(..)
| AssocConstItem(..)
| TyAssocTypeItem(..)
| RequiredAssocConstItem(..)
| ProvidedAssocConstItem(..)
| ImplAssocConstItem(..)
| RequiredAssocTypeItem(..)
| AssocTypeItem(..)
| KeywordItem => kind,
}

View file

@ -334,12 +334,13 @@ impl DocFolder for CacheBuilder<'_, '_> {
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); }

View file

@ -88,7 +88,7 @@ impl<'a> From<&'a clean::Item> for 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 @@ impl<'a> From<&'a clean::Item> for 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,

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 render_impl(
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 render_impl(
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 render_impl(
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 render_impl(
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 render_impl(
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,

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<_>>();

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();

View file

@ -282,10 +282,10 @@ fn sidebar_trait<'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");

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,

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", ""),
]
}

View file

@ -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(_), .. })
)

View file

@ -67,11 +67,12 @@ impl DocFolder for StabilityPropagator<'_, '_> {
// 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,

View file

@ -79,7 +79,10 @@ impl DocFolder for Stripper<'_, '_> {
}
}
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 @@ impl DocFolder for Stripper<'_, '_> {
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(..) => {}

View file

@ -35,7 +35,7 @@ pub(crate) trait DocVisitor<'a>: Sized {
| StaticItem(_)
| ConstantItem(..)
| TraitAliasItem(_)
| TyMethodItem(_)
| RequiredMethodItem(_)
| MethodItem(_, _)
| StructFieldItem(_)
| ForeignFunctionItem(..)
@ -44,9 +44,10 @@ pub(crate) trait DocVisitor<'a>: Sized {
| MacroItem(_)
| ProcMacroItem(_)
| PrimitiveItem(_)
| TyAssocConstItem(..)
| AssocConstItem(..)
| TyAssocTypeItem(..)
| RequiredAssocConstItem(..)
| ProvidedAssocConstItem(..)
| ImplAssocConstItem(..)
| RequiredAssocTypeItem(..)
| AssocTypeItem(..)
| KeywordItem => {}
}

View file

@ -1 +1 @@
214587c89d527dd0ccbe1f2150c737d3bdee67b0
8a1f8039a7ded79d3d4fe97b110016d89f2b11e2

View file

@ -19,6 +19,7 @@ use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, MaybeResult, TyAndLayout};
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,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
/// 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 +957,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 +982,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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]>

View file

@ -24,6 +24,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_session::config::InliningThreshold;
use rustc_span::def_id::{CrateNum, DefId};
use rustc_span::{Span, SpanData, Symbol};
use rustc_target::callconv::FnAbi;
use crate::concurrency::cpu_affinity::{self, CpuAffinityMask};
use crate::concurrency::data_race::{self, NaReadType, NaWriteType};
@ -1010,7 +1011,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
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 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
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>,

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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
// 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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 {

View file

@ -3,14 +3,16 @@ use std::io::Write;
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::ty::Ty;
use rustc_middle::{mir, ty};
use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use self::helpers::{ToHost, ToSoft};
use super::alloc::EvalContextExt as _;
@ -39,7 +41,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 +108,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 +220,7 @@ trait EvalContextExtPriv<'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> {
@ -235,11 +237,10 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 +278,16 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 +297,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
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)
@ -310,8 +311,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
"miri_pointer_name" => {
// 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)?;
let [ptr, nth_parent, name] = 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 +324,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 {
@ -335,8 +335,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.machine.static_roots.push(alloc_id);
}
"miri_host_to_target_path" => {
let [ptr, out, out_size] =
this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
let [ptr, out, out_size] = 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 +371,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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 +385,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
"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() {
@ -427,13 +426,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Aborting the process.
"exit" => {
let [code] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [code] = 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()
))
@ -441,8 +439,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Standard C allocation
"malloc" => {
let [size] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [size] = 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)?;
@ -456,8 +453,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
}
"calloc" => {
let [items, elem_size] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [items, elem_size] = 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) {
@ -472,14 +468,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
}
"free" => {
let [ptr] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [ptr] = 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)?;
let [old_ptr, new_size] = 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 +493,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 +527,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 +553,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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 +588,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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)?;
@ -617,8 +611,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
// C memory handling functions
"memcmp" => {
let [left, right, n] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right, n] = 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)?);
@ -642,8 +635,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_scalar(Scalar::from_i32(result), dest)?;
}
"memrchr" => {
let [ptr, val, num] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [ptr, val, num] = 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)?;
@ -669,8 +661,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
}
"memchr" => {
let [ptr, val, num] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [ptr, val, num] = 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)?;
@ -693,8 +684,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
}
"strlen" => {
let [ptr] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [ptr] = 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();
@ -704,8 +694,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
)?;
}
"wcslen" => {
let [ptr] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [ptr] = 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();
@ -715,8 +704,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
)?;
}
"memcpy" => {
let [ptr_dest, ptr_src, n] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [ptr_dest, ptr_src, n] = 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)?;
@ -730,8 +718,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_pointer(ptr_dest, dest)?;
}
"strcpy" => {
let [ptr_dest, ptr_src] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [ptr_dest, ptr_src] = 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 +747,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
| "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 +775,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
| "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 +804,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
| "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 +832,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
| "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 +853,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
| "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()?;
@ -876,8 +863,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_scalar(res, dest)?;
}
"lgammaf_r" => {
let [x, signp] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [x, signp] = this.check_shim(abi, Conv::C, link_name, args)?;
let x = this.read_scalar(x)?.to_f32()?;
let signp = this.deref_pointer(signp)?;
@ -888,8 +874,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_scalar(res, dest)?;
}
"lgamma_r" => {
let [x, signp] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [x, signp] = this.check_shim(abi, Conv::C, link_name, args)?;
let x = this.read_scalar(x)?.to_f64()?;
let signp = this.deref_pointer(signp)?;
@ -902,8 +887,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
// LLVM intrinsics
"llvm.prefetch" => {
let [p, rw, loc, ty] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [p, rw, loc, ty] = this.check_shim(abi, Conv::C, link_name, args)?;
let _ = this.read_pointer(p)?;
let rw = this.read_scalar(rw)?.to_i32()?;
@ -930,7 +914,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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 +945,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
// 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 +958,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
}
"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 {

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 crate::shims::unix::android::thread::prctl;
use crate::shims::unix::linux_like::epoll::EvalContextExt as _;
@ -16,7 +17,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> {
@ -24,32 +25,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
match link_name.as_str() {
// epoll, eventfd
"epoll_create1" => {
let [flag] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [flag] = 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)?;
let [epfd, op, fd, event] = 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)?;
let [val, flag] = 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)?;
}

View file

@ -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 @@ const TASK_COMM_LEN: usize = 16;
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;

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::Ty;
use rustc_middle::ty::layout::LayoutOf;
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 @@ 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> {
@ -111,54 +113,52 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
"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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
"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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
);
}
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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
);
}
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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
);
}
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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
);
}
// 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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
| "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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
| "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 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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()?;

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 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> {
@ -21,8 +22,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
match link_name.as_str() {
// Threading
"pthread_set_name_np" => {
let [thread, name] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [thread, name] = 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(
@ -33,8 +33,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
)?;
}
"pthread_get_name_np" => {
let [thread, name, len] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [thread, name, len] = 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).
@ -51,33 +50,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// For those, we both intercept `func` and `call@FBSD_1.0` symbols cases
// 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)?;
let [path, buf] = 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)?;
let [path, buf] = 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)?;
let [fd, buf] = 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)?;
let [dirp, entry, result] = 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)?;
}
@ -85,8 +80,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
// 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)?;
let [_thread, _attr] = this.check_shim(abi, Conv::C, link_name, args)?;
this.write_null(dest)?;
}

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 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> {
@ -35,53 +36,47 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
match link_name.as_str() {
// File related shims
"readdir64" => {
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.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)?;
let [fd, offset, nbytes, flags] = 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)?;
}
// epoll, eventfd
"epoll_create1" => {
let [flag] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [flag] = 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)?;
let [epfd, op, fd, event] = 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)?;
let [val, flag] = this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.eventfd(val, flag)?;
this.write_scalar(result, dest)?;
}
// Threading
"pthread_setname_np" => {
let [thread, name] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?;
let res = match this.pthread_setname_np(
this.read_scalar(thread)?,
this.read_scalar(name)?,
@ -96,8 +91,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_scalar(res, dest)?;
}
"pthread_getname_np" => {
let [thread, name, len] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [thread, name, len] = 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 +114,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 +127,34 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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)?;
let [errnum, buf, buflen] = 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)?;
}
@ -169,8 +162,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
// 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)?;
let [_thread, _attr] = this.check_shim(abi, Conv::C, link_name, args)?;
this.write_null(dest)?;
}

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 crate::helpers::check_min_arg_count;
use crate::shims::unix::linux_like::eventfd::EvalContextExt as _;
@ -9,13 +10,13 @@ use crate::*;
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

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::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,66 +26,58 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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)?;
}
// File related shims
"close$NOCANCEL" => {
let [result] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [result] = 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)?;
let [path, buf] = 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)?;
let [path, buf] = 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)?;
let [fd, buf] = 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)?;
let [name] = 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)?;
let [dirp, entry, result] = 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)?;
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)?;
}
// 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)?;
}
// Random data generation
"CCRandomGenerateBytes" => {
let [bytes, count] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [bytes, count] = 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 +87,28 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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)?;
let [info] = 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)?;
let [buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?;
this.check_no_isolation("`_NSGetExecutablePath`")?;
let buf_ptr = this.read_pointer(buf)?;
@ -142,8 +133,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Thread-local storage
"_tlv_atexit" => {
let [dtor, data] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [dtor, data] = 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)?;
@ -153,15 +143,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Querying system information
"pthread_get_stackaddr_np" => {
let [thread] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [thread] = 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)?;
let [thread] = 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)?;
@ -169,8 +157,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Threading
"pthread_setname_np" => {
let [name] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [name] = 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,
@ -197,8 +184,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_scalar(res, dest)?;
}
"pthread_getname_np" => {
let [thread, name, len] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [thread, name, len] = 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)
@ -223,28 +209,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
"os_unfair_lock_lock" => {
let [lock_op] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [lock_op] = 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)?;
let [lock_op] = 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)?;
let [lock_op] = 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)?;
let [lock_op] = 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)?;
let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?;
this.os_unfair_lock_assert_not_owner(lock_op)?;
}

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 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> {
@ -22,8 +23,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
match link_name.as_str() {
// Threading
"pthread_setname_np" => {
let [thread, name] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [thread, name] = 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;
@ -41,8 +41,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_scalar(res, dest)?;
}
"pthread_getname_np" => {
let [thread, name, len] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [thread, name, len] = 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)?,
@ -59,40 +58,35 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// File related shims
"stat" | "stat64" => {
let [path, buf] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [path, buf] = 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)?;
let [path, buf] = 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)?;
let [fd, buf] = 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)?;
let [dirp] = 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)?;
let [stack] = 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(
@ -110,8 +104,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
"pset_info" => {
let [pset, tpe, cpus, list] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [pset, tpe, cpus, list] = 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.
@ -140,8 +133,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
"__sysconf_xpg7" => {
let [val] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [val] = this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.sysconf(val)?;
this.write_scalar(result, dest)?;
}

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 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> {
@ -21,14 +22,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
match link_name.as_str() {
// 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)?;
}
"aligned_alloc" => {
let [align, size] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [align, size] = this.check_shim(abi, Conv::C, link_name, args)?;
let res = this.aligned_alloc(align, size)?;
this.write_pointer(res, dest)?;
}

View file

@ -2,8 +2,10 @@ use std::ffi::OsStr;
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.
@ -100,50 +108,42 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
match link_name.as_str() {
// Environment related shims
"GetEnvironmentVariableW" => {
let [name, buf, size] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [name, buf, size] = 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)?;
let [name, value] = 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)?;
let [] = 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)?;
let [env_block] = 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)?;
let [size, buf] = 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)?;
let [path] = 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)?;
let [token, buf, size] = 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)?;
let [] = this.check_shim(abi, sys_conv, link_name, args)?;
let result = this.GetCurrentProcessId()?;
this.write_scalar(result, dest)?;
}
@ -166,7 +166,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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 +218,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
"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)?;
@ -249,8 +249,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Allocation
"HeapAlloc" => {
let [handle, flags, size] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [handle, flags, size] = 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)?;
@ -273,8 +272,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_pointer(ptr, dest)?;
}
"HeapFree" => {
let [handle, flags, ptr] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [handle, flags, ptr] = 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 +285,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
"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)?;
@ -306,8 +304,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_pointer(new_ptr, dest)?;
}
"LocalFree" => {
let [ptr] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [ptr] = 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)
@ -319,14 +316,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// errno
"SetLastError" => {
let [error] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [error] = 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)?;
let [] = this.check_shim(abi, sys_conv, link_name, args)?;
let last_error = this.get_last_error()?;
this.write_scalar(last_error, dest)?;
}
@ -334,8 +329,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Querying system information
"GetSystemInfo" => {
// Also called from `page_size` crate.
let [system_info] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [system_info] = 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`.
@ -358,22 +352,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// This just creates a key; Windows does not natively support TLS destructors.
// Create key and return it.
let [] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [] = 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)?;
let [key] = 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)?;
this.write_scalar(ptr, dest)?;
}
"TlsSetValue" => {
let [key, new_ptr] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [key, new_ptr] = 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 +374,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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)?;
@ -394,8 +384,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Access to command-line arguments
"GetCommandLineW" => {
let [] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [] = this.check_shim(abi, sys_conv, link_name, args)?;
this.write_pointer(
this.machine.cmd_line.expect("machine must be initialized"),
dest,
@ -405,33 +394,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Time related shims
"GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => {
#[allow(non_snake_case)]
let [LPFILETIME] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [LPFILETIME] = 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)?;
let [lpPerformanceCount] = 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)?;
let [lpFrequency] = 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)?;
let [timeout] = 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 +430,27 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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)?;
let [ptr, flags, context] = 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)?;
let [ptr_op] = 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)?;
let [ptr_op] = this.check_shim(abi, sys_conv, link_name, args)?;
this.WakeByAddressAll(ptr_op)?;
}
@ -476,8 +458,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Dynamic symbol loading
"GetProcAddress" => {
#[allow(non_snake_case)]
let [hModule, lpProcName] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [hModule, lpProcName] = 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 +474,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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)?;
@ -501,15 +482,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?;
}
"WaitForSingleObject" => {
let [handle, timeout] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [handle, timeout] = 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)?;
let [] = this.check_shim(abi, sys_conv, link_name, args)?;
this.write_scalar(
Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this),
@ -517,8 +496,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
)?;
}
"SetThreadDescription" => {
let [handle, name] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [handle, name] = 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)?)?;
@ -542,8 +520,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_scalar(res, dest)?;
}
"GetThreadDescription" => {
let [handle, name_ptr] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [handle, name_ptr] = 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
@ -574,16 +551,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Miscellaneous
"ExitProcess" => {
let [code] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [code] = 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 });
}
"SystemFunction036" => {
// used by getrandom 0.1
// This is really 'RtlGenRandom'.
let [ptr, len] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [ptr, len] = 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())?;
@ -591,8 +566,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
"ProcessPrng" => {
// used by `std`
let [ptr, len] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [ptr, len] = 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 +575,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"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)?;
@ -635,8 +609,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
"GetConsoleScreenBufferInfo" => {
// `term` needs this, so we fake it.
let [console, buffer_info] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [console, buffer_info] = 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)?;
@ -645,8 +618,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_null(dest)?;
}
"GetStdHandle" => {
let [which] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [which] = 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
@ -655,16 +627,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_scalar(Scalar::from_target_isize(which.into(), this), dest)?;
}
"CloseHandle" => {
let [handle] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [handle] = this.check_shim(abi, sys_conv, link_name, args)?;
let ret = this.CloseHandle(handle)?;
this.write_scalar(ret, dest)?;
}
"GetModuleFileNameW" => {
let [handle, filename, size] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [handle, filename, size] = this.check_shim(abi, sys_conv, link_name, args)?;
this.check_no_isolation("`GetModuleFileNameW`")?;
let handle = this.read_target_usize(handle)?;
@ -698,7 +668,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
"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
@ -733,29 +703,26 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
// 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)?;
let [] = 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)?;
}
"GetModuleHandleA" if this.frame_in_std() => {
#[allow(non_snake_case)]
let [_lpModuleName] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [_lpModuleName] = 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)?;
let [console, mode] = this.check_shim(abi, sys_conv, link_name, args)?;
this.read_target_isize(console)?;
this.deref_pointer(mode)?;
// Indicate an error.
@ -763,29 +730,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
"GetFileType" if this.frame_in_std() => {
#[allow(non_snake_case)]
let [_hFile] =
this.check_shim(abi, ExternAbi::System { unwind: false }, link_name, args)?;
let [_hFile] = 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)?;
let [_First, _Handler] = 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)?;
let [_StackSizeInBytes] = 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)?;
let [] = this.check_shim(abi, sys_conv, link_name, args)?;
this.yield_active_thread();
@ -804,8 +767,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
);
}
// 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);
}

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> {
@ -26,9 +26,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// `state` with the corresponding 128-bit key of `key`.
// 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)?;
let [state, key] = 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());
@ -44,8 +42,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// `state` with the corresponding 128-bit key of `key`.
// 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)?;
let [state, key] = 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());
@ -69,9 +66,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// `state` with the corresponding 128-bit key of `key`.
// 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)?;
let [state, key] = 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());
@ -87,9 +82,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// `state` with the corresponding 128-bit key of `key`.
// 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)?;
let [state, key] = 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 +102,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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)?;

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> {
@ -33,8 +33,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// matches the IEEE min/max operations, while x86 has different
// semantics.
"min.ps.256" | "max.ps.256" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"min.ps.256" => FloatBinOp::Min,
@ -46,8 +45,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
// 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)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"min.pd.256" => FloatBinOp::Min,
@ -60,23 +58,21 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Used to implement the _mm256_round_ps function.
// 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)?;
let [op, rounding] = this.check_shim(abi, Conv::C, link_name, args)?;
round_all::<rustc_apfloat::ieee::Single>(this, op, rounding, dest)?;
}
// Used to implement the _mm256_round_pd function.
// 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)?;
let [op, rounding] = 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,
@ -88,8 +84,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
// 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)?;
let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
conditional_dot_product(this, left, right, imm, dest)?;
}
@ -97,8 +92,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Horizontally add/subtract adjacent floating point values
// 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)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"hadd.ps.256" | "hadd.pd.256" => mir::BinOp::Add,
@ -113,8 +107,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// and `right`. For each component, returns 0 if false or u32::MAX
// if true.
"cmp.ps.256" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@ -126,8 +119,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// and `right`. For each component, returns 0 if false or u64::MAX
// if true.
"cmp.pd.256" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right, imm] = 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 +130,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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
@ -156,8 +148,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// sequence of 4-element arrays, and we shuffle each of these arrays, where
// `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)?;
let [data, control] = 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)?;
@ -190,8 +181,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// where `right` determines which element of the current `left` array is
// written.
"vpermilvar.pd" | "vpermilvar.pd.256" => {
let [data, control] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [data, control] = 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)?;
@ -223,8 +213,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// For each 128-bit element of `dest`, copies one from `left`, `right` or
// 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)?;
let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
assert_eq!(dest.layout, left.layout);
assert_eq!(dest.layout, right.layout);
@ -267,8 +256,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// is one, it is loaded from `ptr.wrapping_add(i)`, otherwise zero is
// 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)?;
let [ptr, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
mask_load(this, ptr, mask, dest)?;
}
@ -278,8 +266,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// is one, it is stored into `ptr.wapping_add(i)`.
// 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)?;
let [ptr, mask, value] = this.check_shim(abi, Conv::C, link_name, args)?;
mask_store(this, ptr, mask, value)?;
}
@ -289,8 +276,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// the data crosses a cache line, but for Miri this is just a regular
// unaligned read.
"ldu.dq.256" => {
let [src_ptr] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [src_ptr] = this.check_shim(abi, Conv::C, link_name, args)?;
let src_ptr = this.read_pointer(src_ptr)?;
let dest = dest.force_mplace(this)?;
@ -302,8 +288,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Tests `op & mask == 0`, `op & mask == mask` or
// `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)?;
let [op, mask] = 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 {
@ -326,8 +311,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"vtestz.pd.256" | "vtestc.pd.256" | "vtestnzc.pd.256" | "vtestz.pd" | "vtestc.pd"
| "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)?;
let [op, mask] = 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 +333,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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),
}

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 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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)?;
}
@ -36,8 +36,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Horizontally add / add with saturation / subtract adjacent 16/32-bit
// 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)?;
let [left, right] = 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 +57,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
| "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);
@ -115,8 +114,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// intermediate signed 32-bit integers. Horizontally add adjacent pairs of
// 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)?;
let [left, right] = 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)?;
@ -152,8 +150,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// the saturating sum of the products with indices `2*i` and `2*i+1`
// produces the output at index `i`.
"pmadd.ub.sw" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right] = 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)?;
@ -187,8 +184,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// is one, it is loaded from `ptr.wrapping_add(i)`, otherwise zero is
// 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)?;
let [ptr, mask] = this.check_shim(abi, Conv::C, link_name, args)?;
mask_load(this, ptr, mask, dest)?;
}
@ -198,8 +194,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// is one, it is stored into `ptr.wapping_add(i)`.
// 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)?;
let [ptr, mask, value] = this.check_shim(abi, Conv::C, link_name, args)?;
mask_store(this, ptr, mask, value)?;
}
@ -210,8 +205,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// offsets specified in `imm`.
// 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)?;
let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
mpsadbw(this, left, right, imm, dest)?;
}
@ -222,8 +216,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 1 and then taking the bits `1..=16`.
// 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)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
pmulhrsw(this, left, right, dest)?;
}
@ -231,8 +224,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Converts two 16-bit integer vectors to a single 8-bit integer
// vector with signed saturation.
"packsswb" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
packsswb(this, left, right, dest)?;
}
@ -240,8 +232,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Converts two 32-bit integer vectors to a single 16-bit integer
// vector with signed saturation.
"packssdw" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
packssdw(this, left, right, dest)?;
}
@ -249,8 +240,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Converts two 16-bit signed integer vectors to a single 8-bit
// unsigned integer vector with saturation.
"packuswb" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
packuswb(this, left, right, dest)?;
}
@ -258,8 +248,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Concatenates two 32-bit signed integer vectors and converts
// 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)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
packusdw(this, left, right, dest)?;
}
@ -268,8 +257,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Shuffles `left` using the three low bits of each element of `right`
// as indices.
"permd" | "permps" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right] = 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)?;
@ -289,8 +277,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Used to implement the _mm256_permute2x128_si256 function.
// 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)?;
let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
assert_eq!(left.layout.size.bits(), 256);
assert_eq!(right.layout.size.bits(), 256);
@ -327,8 +314,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// in `dest`.
// 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)?;
let [left, right] = 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)?;
@ -360,8 +346,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Shuffles bytes from `left` using `right` as pattern.
// Each 128-bit block is shuffled independently.
"pshuf.b" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right] = 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)?;
@ -392,8 +377,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// is writen to the corresponding output element.
// 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)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
psign(this, left, right, dest)?;
}
@ -407,8 +391,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// is copied to remaining bits.
"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)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"psll.w" | "psll.d" | "psll.q" => ShiftOp::Left,
@ -423,8 +406,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// (except _mm{,256}_srav_epi64, which are not available in AVX2).
"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)?;
let [left, right] = 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,

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 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> {
@ -33,8 +34,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
return interp_ok(EmulateItemResult::NotSupported);
}
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
let left = this.read_scalar(left)?;
let right = this.read_scalar(right)?;

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 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> {
@ -29,16 +30,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// See `affine_transform` for details.
// 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)?;
let [left, right, imm8] = 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.
// See `affine_transform` for details.
// 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)?;
let [left, right, imm8] = 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.
@ -47,9 +46,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// polynomial representation with the reduction polynomial x^8 + x^4 + x^3 + x + 1.
// 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)?;
let [left, right] = 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)?;

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 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
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)?;
let [c_in, a, b, out] = 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 +85,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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();
@ -106,8 +104,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
len = 8;
}
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
pclmulqdq(this, left, right, imm, dest, len)?;
}

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> {
@ -51,8 +52,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
match unprefixed_name {
// Used to implement the _mm_sha256rnds2_epu32 function.
"256rnds2" => {
let [a, b, k] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [a, b, k] = 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)?;
@ -73,8 +73,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
// Used to implement the _mm_sha256msg1_epu32 function.
"256msg1" => {
let [a, b] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [a, b] = 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)?;
@ -92,8 +91,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
// Used to implement the _mm_sha256msg2_epu32 function.
"256msg2" => {
let [a, b] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [a, b] = 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)?;

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> {
@ -32,8 +33,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Performs the operations on the first component of `left` and
// `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)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"min.ss" => FloatBinOp::Min,
@ -49,8 +49,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// matches the IEEE min/max operations, while x86 has different
// semantics.
"min.ps" | "max.ps" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"min.ps" => FloatBinOp::Min,
@ -64,7 +63,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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 +76,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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,
@ -96,8 +95,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_ss are SSE functions
// with hard-coded operations.
"cmp.ss" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@ -113,8 +111,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_ps are SSE functions
// with hard-coded operations.
"cmp.ps" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right, imm] = 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,8 +124,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"comieq.ss" | "comilt.ss" | "comile.ss" | "comigt.ss" | "comige.ss" | "comineq.ss"
| "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)?;
let [left, right] = 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 +152,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// _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)?)?;
@ -184,8 +180,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// are copied from `left`.
// https://www.felixcloutier.com/x86/cvtsi2ss
"cvtsi2ss" | "cvtsi642ss" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right] = 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)?;

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> {
@ -39,8 +40,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// intermediate signed 32-bit integers. Horizontally add adjacent pairs of
// 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)?;
let [left, right] = 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)?;
@ -78,8 +78,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
//
// 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)?;
let [left, right] = 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)?;
@ -117,8 +116,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// is copied to remaining bits.
"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)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"psll.w" | "psll.d" | "psll.q" => ShiftOp::Left,
@ -133,7 +131,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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);
@ -170,8 +168,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Converts two 16-bit integer vectors to a single 8-bit integer
// vector with signed saturation.
"packsswb.128" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
packsswb(this, left, right, dest)?;
}
@ -179,8 +176,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Converts two 16-bit signed integer vectors to a single 8-bit
// unsigned integer vector with saturation.
"packuswb.128" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
packuswb(this, left, right, dest)?;
}
@ -188,8 +184,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Converts two 32-bit integer vectors to a single 16-bit integer
// vector with signed saturation.
"packssdw.128" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
packssdw(this, left, right, dest)?;
}
@ -199,8 +194,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// matches the IEEE min/max operations, while x86 has different
// semantics.
"min.sd" | "max.sd" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"min.sd" => FloatBinOp::Min,
@ -216,8 +210,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// matches the IEEE min/max operations, while x86 has different
// semantics.
"min.pd" | "max.pd" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"min.pd" => FloatBinOp::Min,
@ -236,8 +229,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_sd are SSE2 functions
// with hard-coded operations.
"cmp.sd" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@ -253,8 +245,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_pd are SSE2 functions
// with hard-coded operations.
"cmp.pd" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
let which =
FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?;
@ -267,8 +258,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"comieq.sd" | "comilt.sd" | "comile.sd" | "comigt.sd" | "comige.sd" | "comineq.sd"
| "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)?;
let [left, right] = 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 +286,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// _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)?)?;
@ -322,8 +312,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Converts the first f64/f32 from `right` to f32/f64 and copies
// the remaining elements from `left`
"cvtsd2ss" | "cvtss2sd" => {
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right] = 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)?;

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> {
@ -24,8 +25,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Horizontally add/subtract adjacent floating point values
// 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)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
let which = match unprefixed_name {
"hadd.ps" | "hadd.pd" => mir::BinOp::Add,
@ -41,8 +41,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// the data crosses a cache line, but for Miri this is just a regular
// unaligned read.
"ldu.dq" => {
let [src_ptr] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [src_ptr] = this.check_shim(abi, Conv::C, link_name, args)?;
let src_ptr = this.read_pointer(src_ptr)?;
let dest = dest.force_mplace(this)?;

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> {
@ -26,8 +27,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// bits `4..=5` if `imm`, and `i`th bit specifies whether element
// `i` is zeroed.
"insertps" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right, imm] = 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,8 +62,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Concatenates two 32-bit signed integer vectors and converts
// 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)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
packusdw(this, left, right, dest)?;
}
@ -73,8 +72,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// products, and conditionally stores the sum in `dest` using the low
// 4 bits of `imm`.
"dpps" | "dppd" => {
let [left, right, imm] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
conditional_dot_product(this, left, right, imm, dest)?;
}
@ -82,16 +80,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// functions. Rounds the first element of `right` according to `rounding`
// and copies the remaining elements from `left`.
"round.ss" => {
let [left, right, rounding] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right, rounding] = this.check_shim(abi, Conv::C, link_name, args)?;
round_first::<rustc_apfloat::ieee::Single>(this, left, right, rounding, dest)?;
}
// Used to implement the _mm_floor_ps, _mm_ceil_ps and _mm_round_ps
// 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)?;
let [op, rounding] = this.check_shim(abi, Conv::C, link_name, args)?;
round_all::<rustc_apfloat::ieee::Single>(this, op, rounding, dest)?;
}
@ -99,16 +95,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// functions. Rounds the first element of `right` according to `rounding`
// and copies the remaining elements from `left`.
"round.sd" => {
let [left, right, rounding] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right, rounding] = this.check_shim(abi, Conv::C, link_name, args)?;
round_first::<rustc_apfloat::ieee::Double>(this, left, right, rounding, dest)?;
}
// Used to implement the _mm_floor_pd, _mm_ceil_pd and _mm_round_pd
// 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)?;
let [op, rounding] = this.check_shim(abi, Conv::C, link_name, args)?;
round_all::<rustc_apfloat::ieee::Double>(this, op, rounding, dest)?;
}
@ -116,7 +110,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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)?;
@ -150,8 +144,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// offsets specified in `imm`.
// 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)?;
let [left, right, imm] = this.check_shim(abi, Conv::C, link_name, args)?;
mpsadbw(this, left, right, imm, dest)?;
}
@ -160,8 +153,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Tests `(op & mask) == 0`, `(op & mask) == mask` or
// `(op & mask) != 0 && (op & mask) != mask`
"ptestz" | "ptestc" | "ptestnzc" => {
let [op, mask] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [op, mask] = 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 {

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| {
@ -222,8 +223,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)?;
let [str1, len1, str2, len2, imm] = ecx.check_shim(abi, Conv::C, link_name, args)?;
let imm = ecx.read_scalar(imm)?.to_u8()?;
let default_len = default_len::<u32>(imm);
@ -236,8 +236,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)?;
let [str1, str2, imm] = 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 +278,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> {
@ -387,8 +386,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// search for a null terminator (see `deconstruct_args` for more details).
// 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)?;
let [str1, str2, imm] = 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 };
@ -408,8 +406,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// than 16 for byte-sized operands or 8 for word-sized operands.
// 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)?;
let [_, len1, _, len2, imm] = 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()?;
@ -436,8 +433,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
return interp_ok(EmulateItemResult::NotSupported);
}
let [left, right] =
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
let left = this.read_scalar(left)?;
let right = this.read_scalar(right)?;

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 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 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)?;
}
@ -31,8 +32,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Shuffles bytes from `left` using `right` as pattern.
// 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)?;
let [left, right] = 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)?;
@ -61,8 +61,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// integer values in `left` and `right`.
"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)?;
let [left, right] = 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),
@ -81,8 +80,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// produces the output at index `i`.
// 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)?;
let [left, right] = 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)?;
@ -117,8 +115,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// 1 and then taking the bits `1..=16`.
// 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)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
pmulhrsw(this, left, right, dest)?;
}
@ -128,8 +125,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// is writen to the corresponding output element.
// 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)?;
let [left, right] = this.check_shim(abi, Conv::C, link_name, args)?;
psign(this, left, right, dest)?;
}

View file

@ -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`

View file

@ -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;

View file

@ -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

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;

View file

@ -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

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: () };
}

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>();
}