Auto merge of #151352 - Zalathar:rollup-nUIzD3P, r=Zalathar
Rollup of 4 pull requests Successful merges: - rust-lang/rust#151080 (fix(build-manifest): enable docs target fallback for `rustc-docs`) - rust-lang/rust#151328 (Fix capitalization of diag messages) - rust-lang/rust#151341 (miri subtree update) - rust-lang/rust#151349 (Add myself to the review rotation) r? @ghost
This commit is contained in:
commit
53b6f89be2
69 changed files with 1390 additions and 799 deletions
|
|
@ -230,7 +230,7 @@ attr_parsing_unstable_cfg_target_compact =
|
|||
compact `cfg(target(..))` is experimental and subject to change
|
||||
|
||||
attr_parsing_unstable_feature_bound_incompatible_stability = item annotated with `#[unstable_feature_bound]` should not be stable
|
||||
.help = If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]`
|
||||
.help = if this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]`
|
||||
|
||||
attr_parsing_unsupported_instruction_set = target `{$current_target}` does not support `#[instruction_set({$instruction_set}::*)]`
|
||||
|
||||
|
|
|
|||
|
|
@ -140,9 +140,9 @@ const_eval_incompatible_return_types =
|
|||
const_eval_interior_mutable_borrow_escaping =
|
||||
interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
|
||||
.label = this borrow of an interior mutable value refers to such a temporary
|
||||
.note = Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
.note2 = To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
.help = If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
.note = temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
.note2 = to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
.help = if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
const_eval_intern_kind = {$kind ->
|
||||
[static] static
|
||||
|
|
@ -225,9 +225,9 @@ const_eval_modified_global =
|
|||
const_eval_mutable_borrow_escaping =
|
||||
mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
|
||||
.label = this mutable borrow refers to such a temporary
|
||||
.note = Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
.note2 = To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
.help = If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
.note = temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
.note2 = to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
.help = if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind}
|
||||
|
||||
|
|
|
|||
|
|
@ -542,7 +542,7 @@ lint_invalid_style = {$is_used_as_inner ->
|
|||
[false] crate-level attribute should be an inner attribute: add an exclamation mark: `#![{$name}]`
|
||||
*[other] the `#![{$name}]` attribute can only be used at the crate root
|
||||
}
|
||||
.note = This attribute does not have an `!`, which means it is applied to this {$target}
|
||||
.note = this attribute does not have an `!`, which means it is applied to this {$target}
|
||||
|
||||
lint_invalid_target = `#[{$name}]` attribute cannot be used on {$target}
|
||||
.warn = {-lint_previously_accepted}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ monomorphize_encountered_error_while_instantiating_global_asm =
|
|||
monomorphize_large_assignments =
|
||||
moving {$size} bytes
|
||||
.label = value moved from here
|
||||
.note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
.note = the current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
|
||||
monomorphize_no_optimized_mir =
|
||||
missing optimized MIR for `{$instance}` in the crate `{$crate_name}`
|
||||
|
|
|
|||
|
|
@ -376,7 +376,7 @@ passes_no_main_function =
|
|||
}
|
||||
.consider_adding_main_to_file = consider adding a `main` function to `{$filename}`
|
||||
.consider_adding_main_at_crate = consider adding a `main` function at the crate level
|
||||
.teach_note = If you don't know the basics of Rust, you can go look to the Rust Book to get started: https://doc.rust-lang.org/book/
|
||||
.teach_note = if you don't know the basics of Rust, you can go look to the Rust Book to get started: https://doc.rust-lang.org/book/
|
||||
.non_function_main = non-function item at `crate::main` is found
|
||||
|
||||
passes_non_exhaustive_with_default_field_values =
|
||||
|
|
|
|||
|
|
@ -14,11 +14,11 @@ use crate::versions::{PkgType, Versions};
|
|||
|
||||
include!(concat!(env!("OUT_DIR"), "/targets.rs"));
|
||||
|
||||
/// This allows the manifest to contain rust-docs for hosts that don't build
|
||||
/// docs.
|
||||
/// This allows the manifest to contain rust-docs and rustc-docs for hosts
|
||||
/// that don't build certain docs.
|
||||
///
|
||||
/// Tuples of `(host_partial, host_instead)`. If the host does not have the
|
||||
/// rust-docs component available, then if the host name contains
|
||||
/// corresponding docs component available, then if the host name contains
|
||||
/// `host_partial`, it will use the docs from `host_instead` instead.
|
||||
///
|
||||
/// The order here matters, more specific entries should be first.
|
||||
|
|
@ -392,9 +392,9 @@ impl Builder {
|
|||
let t = Target::from_compressed_tar(self, &tarball_name!(fallback_target));
|
||||
// Fallbacks should typically be available on 'production' builds
|
||||
// but may not be available for try builds, which only build one target by
|
||||
// default. Ideally we'd gate this being a hard error on whether we're in a
|
||||
// production build or not, but it's not information that's readily available
|
||||
// here.
|
||||
// default. It is also possible that `rust-docs` and `rustc-docs` differ in
|
||||
// availability per target. Thus, we take the first available fallback we can
|
||||
// find.
|
||||
if !t.available {
|
||||
eprintln!(
|
||||
"{:?} not available for fallback",
|
||||
|
|
|
|||
|
|
@ -133,10 +133,7 @@ impl PkgType {
|
|||
|
||||
/// Whether to package these target-specific docs for another similar target.
|
||||
pub(crate) fn use_docs_fallback(&self) -> bool {
|
||||
match self {
|
||||
PkgType::JsonDocs | PkgType::HtmlDocs => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self, PkgType::JsonDocs | PkgType::HtmlDocs | PkgType::RustcDocs)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -228,7 +228,8 @@ and macOS targets are usually on par. Windows is supported less well.
|
|||
|
||||
### Running tests in parallel
|
||||
|
||||
Though it implements Rust threading, Miri itself is a single-threaded interpreter.
|
||||
Though it implements Rust threading, Miri itself is a single-threaded interpreter
|
||||
(it works like a multi-threaded OS on a single-core CPU).
|
||||
This means that when running `cargo miri test`, you will probably see a dramatic
|
||||
increase in the amount of time it takes to run your whole test suite due to the
|
||||
inherent interpreter slowdown and a loss of parallelism.
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
f57b9e6f565a1847e83a63f3e90faa3870536c1f
|
||||
b6fdaf2a15736cbccf248b532f48e33179614d40
|
||||
|
|
|
|||
|
|
@ -710,7 +710,7 @@ fn main() {
|
|||
if !miri_config.native_lib.is_empty() && miri_config.provenance_mode == ProvenanceMode::Strict {
|
||||
fatal_error!("strict provenance is not compatible with calling native functions");
|
||||
}
|
||||
// Native calls and many-seeds are an "intersting" combination.
|
||||
// Native calls and many-seeds are an "interesting" combination.
|
||||
if !miri_config.native_lib.is_empty() && many_seeds.is_some() {
|
||||
eprintln!(
|
||||
"warning: `-Zmiri-many-seeds` runs multiple instances of the program in the same address space, \
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::collections::hash_map::Entry;
|
|||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
use rustc_abi::{Align, CanonAbi, Size};
|
||||
use rustc_abi::{Align, CanonAbi, ExternAbi, Size};
|
||||
use rustc_ast::expand::allocator::NO_ALLOC_SHIM_IS_UNSTABLE;
|
||||
use rustc_data_structures::either::Either;
|
||||
use rustc_hir::attrs::Linkage;
|
||||
|
|
@ -435,6 +435,40 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
// Return value: 0 on success, otherwise the size it would have needed.
|
||||
this.write_int(if success { 0 } else { needed_size }, dest)?;
|
||||
}
|
||||
"miri_thread_spawn" => {
|
||||
// FIXME: `check_shim_sig` does not work with function pointers.
|
||||
let [start_routine, func_arg] =
|
||||
this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
|
||||
let start_routine = this.read_pointer(start_routine)?;
|
||||
let func_arg = this.read_immediate(func_arg)?;
|
||||
|
||||
this.start_regular_thread(
|
||||
Some(dest.clone()),
|
||||
start_routine,
|
||||
ExternAbi::Rust,
|
||||
func_arg,
|
||||
this.machine.layouts.unit,
|
||||
)?;
|
||||
}
|
||||
"miri_thread_join" => {
|
||||
let [thread_id] = this.check_shim_sig(
|
||||
shim_sig!(extern "Rust" fn(usize) -> bool),
|
||||
link_name,
|
||||
abi,
|
||||
args,
|
||||
)?;
|
||||
|
||||
let thread = this.read_target_usize(thread_id)?;
|
||||
if let Ok(thread) = this.thread_id_try_from(thread) {
|
||||
this.join_thread_exclusive(
|
||||
thread,
|
||||
/* success_retval */ Scalar::from_bool(true),
|
||||
dest,
|
||||
)?;
|
||||
} else {
|
||||
this.write_scalar(Scalar::from_bool(false), dest)?;
|
||||
}
|
||||
}
|
||||
// Hint that a loop is spinning indefinitely.
|
||||
"miri_spin_loop" => {
|
||||
let [] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
|
||||
|
|
|
|||
|
|
@ -17,11 +17,18 @@ pub struct ShimSig<'tcx, const ARGS: usize> {
|
|||
|
||||
/// Construct a `ShimSig` with convenient syntax:
|
||||
/// ```rust,ignore
|
||||
/// shim_sig!(this, extern "C" fn (*const T, i32) -> usize)
|
||||
/// shim_sig!(extern "C" fn (*const T, i32) -> usize)
|
||||
/// ```
|
||||
///
|
||||
/// The following types are supported:
|
||||
/// - primitive integer types
|
||||
/// - `()`
|
||||
/// - (thin) raw pointers, written `*const _` and `*mut _` since the pointee type is irrelevant
|
||||
/// - `$crate::$mod::...::$ty` for a type from the given crate (most commonly that is `libc`)
|
||||
/// - `winapi::$ty` for a type from `std::sys::pal::windows::c`
|
||||
#[macro_export]
|
||||
macro_rules! shim_sig {
|
||||
(extern $abi:literal fn($($arg:ty),*) -> $ret:ty) => {
|
||||
(extern $abi:literal fn($($arg:ty),* $(,)?) -> $ret:ty) => {
|
||||
|this| $crate::shims::sig::ShimSig {
|
||||
abi: std::str::FromStr::from_str($abi).expect("incorrect abi specified"),
|
||||
args: [$(shim_sig_arg!(this, $arg)),*],
|
||||
|
|
@ -50,9 +57,13 @@ macro_rules! shim_sig_arg {
|
|||
"u128" => $this.tcx.types.u128,
|
||||
"usize" => $this.tcx.types.usize,
|
||||
"()" => $this.tcx.types.unit,
|
||||
"bool" => $this.tcx.types.bool,
|
||||
"*const _" => $this.machine.layouts.const_raw_ptr.ty,
|
||||
"*mut _" => $this.machine.layouts.mut_raw_ptr.ty,
|
||||
ty if let Some(libc_ty) = ty.strip_prefix("libc::") => $this.libc_ty_layout(libc_ty).ty,
|
||||
ty if let Some(win_ty) = ty.strip_prefix("winapi::") =>
|
||||
$this.windows_ty_layout(win_ty).ty,
|
||||
ty if ty.contains("::") =>
|
||||
helpers::path_ty_layout($this, &ty.split("::").collect::<Vec<_>>()).ty,
|
||||
ty => panic!("unsupported signature type {ty:?}"),
|
||||
}
|
||||
}};
|
||||
|
|
|
|||
|
|
@ -28,21 +28,25 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
match link_name.as_str() {
|
||||
// File related shims
|
||||
"stat" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let result = this.stat(path, buf)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"lstat" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let result = this.lstat(path, buf)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"readdir" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let result = this.readdir64("dirent", dirp)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"pread64" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [fd, buf, count, offset] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off64_t) -> isize),
|
||||
link_name,
|
||||
|
|
@ -56,6 +60,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.read(fd, buf, count, Some(offset), dest)?;
|
||||
}
|
||||
"pwrite64" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [fd, buf, n, offset] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(i32, *const _, usize, libc::off64_t) -> isize),
|
||||
link_name,
|
||||
|
|
@ -70,6 +75,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write(fd, buf, count, Some(offset), dest)?;
|
||||
}
|
||||
"lseek64" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [fd, offset, whence] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(i32, libc::off64_t, i32) -> libc::off64_t),
|
||||
link_name,
|
||||
|
|
|
|||
|
|
@ -143,6 +143,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"getcwd" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [buf, size] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(*mut _, usize) -> *mut _),
|
||||
link_name,
|
||||
|
|
@ -153,6 +154,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_pointer(result, dest)?;
|
||||
}
|
||||
"chdir" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [path] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(*const _) -> i32),
|
||||
link_name,
|
||||
|
|
@ -209,6 +211,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write(fd, buf, count, None, dest)?;
|
||||
}
|
||||
"pread" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [fd, buf, count, offset] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off_t) -> isize),
|
||||
link_name,
|
||||
|
|
@ -222,6 +225,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.read(fd, buf, count, Some(offset), dest)?;
|
||||
}
|
||||
"pwrite" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [fd, buf, n, offset] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(i32, *const _, usize, libc::off_t) -> isize),
|
||||
link_name,
|
||||
|
|
@ -299,6 +303,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"unlink" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [path] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(*const _) -> i32),
|
||||
link_name,
|
||||
|
|
@ -309,6 +314,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"symlink" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [target, linkpath] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(*const _, *const _) -> i32),
|
||||
link_name,
|
||||
|
|
@ -324,6 +330,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"rename" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [oldpath, newpath] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(*const _, *const _) -> i32),
|
||||
link_name,
|
||||
|
|
@ -334,6 +341,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"mkdir" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [path, mode] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(*const _, libc::mode_t) -> i32),
|
||||
link_name,
|
||||
|
|
@ -344,6 +352,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"rmdir" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [path] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(*const _) -> i32),
|
||||
link_name,
|
||||
|
|
@ -354,6 +363,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"opendir" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [name] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(*const _) -> *mut _),
|
||||
link_name,
|
||||
|
|
@ -364,6 +374,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"closedir" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [dirp] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(*mut _) -> i32),
|
||||
link_name,
|
||||
|
|
@ -374,6 +385,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"lseek" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [fd, offset, whence] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(i32, libc::off_t, i32) -> libc::off_t),
|
||||
link_name,
|
||||
|
|
@ -398,6 +410,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"fsync" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [fd] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(i32) -> i32),
|
||||
link_name,
|
||||
|
|
@ -408,6 +421,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"fdatasync" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [fd] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(i32) -> i32),
|
||||
link_name,
|
||||
|
|
@ -659,6 +673,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_null(dest)?;
|
||||
}
|
||||
"pthread_key_delete" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
|
||||
this.machine.tls.delete_tls_key(key)?;
|
||||
|
|
@ -666,6 +681,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_null(dest)?;
|
||||
}
|
||||
"pthread_getspecific" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
|
||||
let active_thread = this.active_thread();
|
||||
|
|
@ -673,6 +689,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(ptr, dest)?;
|
||||
}
|
||||
"pthread_setspecific" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [key, new_ptr] =
|
||||
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
|
||||
|
|
@ -833,6 +850,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(res, dest)?;
|
||||
}
|
||||
"sched_yield" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
this.sched_yield()?;
|
||||
this.write_null(dest)?;
|
||||
|
|
@ -941,6 +959,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"pthread_atfork" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [prepare, parent, child] =
|
||||
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
this.read_pointer(prepare)?;
|
||||
|
|
|
|||
|
|
@ -139,11 +139,13 @@ 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" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let result = this.stat(path, buf)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"lstat" | "lstat@FBSD_1.0" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let result = this.lstat(path, buf)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
|
|
@ -154,6 +156,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"readdir" | "readdir@FBSD_1.0" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let result = this.readdir64("dirent", dirp)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"pread64" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [fd, buf, count, offset] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off64_t) -> isize),
|
||||
link_name,
|
||||
|
|
@ -58,6 +59,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.read(fd, buf, count, Some(offset), dest)?;
|
||||
}
|
||||
"pwrite64" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [fd, buf, n, offset] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(i32, *const _, usize, libc::off64_t) -> isize),
|
||||
link_name,
|
||||
|
|
@ -72,6 +74,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write(fd, buf, count, Some(offset), dest)?;
|
||||
}
|
||||
"lseek64" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [fd, offset, whence] = this.check_shim_sig(
|
||||
shim_sig!(extern "C" fn(i32, libc::off64_t, i32) -> libc::off64_t),
|
||||
link_name,
|
||||
|
|
@ -111,6 +114,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"readdir64" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let result = this.readdir64("dirent64", dirp)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
|
|
@ -122,6 +126,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"statx" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [dirfd, pathname, flags, mask, statxbuf] =
|
||||
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?;
|
||||
|
|
|
|||
|
|
@ -47,11 +47,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"stat" | "stat$INODE64" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let result = this.stat(path, buf)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"lstat" | "lstat$INODE64" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let result = this.lstat(path, buf)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
|
|
@ -62,11 +64,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"opendir$INODE64" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [name] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let result = this.opendir(name)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"readdir_r" | "readdir_r$INODE64" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [dirp, entry, result] =
|
||||
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let result = this.macos_readdir_r(dirp, entry, result)?;
|
||||
|
|
@ -87,6 +91,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
|
||||
// Environment related shims
|
||||
"_NSGetEnviron" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let environ = this.machine.env_vars.unix().environ();
|
||||
this.write_pointer(environ, dest)?;
|
||||
|
|
@ -111,6 +116,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
}
|
||||
|
||||
"mach_timebase_info" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [info] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let result = this.mach_timebase_info(info)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
|
|
@ -118,14 +124,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
|
||||
// Access to command-line arguments
|
||||
"_NSGetArgc" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
this.write_pointer(this.machine.argc.expect("machine must be initialized"), dest)?;
|
||||
}
|
||||
"_NSGetArgv" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
this.write_pointer(this.machine.argv.expect("machine must be initialized"), dest)?;
|
||||
}
|
||||
"_NSGetExecutablePath" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [buf, bufsize] =
|
||||
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
this.check_no_isolation("`_NSGetExecutablePath`")?;
|
||||
|
|
@ -168,12 +177,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
|
||||
// Querying system information
|
||||
"pthread_get_stackaddr_np" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::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" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
this.read_target_usize(thread)?;
|
||||
let stack_size = Scalar::from_uint(this.machine.stack_size, this.pointer_size());
|
||||
|
|
|
|||
|
|
@ -91,16 +91,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
|
||||
// File related shims
|
||||
"stat" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let result = this.stat(path, buf)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"lstat" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let result = this.lstat(path, buf)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"readdir" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let result = this.readdir64("dirent", dirp)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
|
|
@ -122,6 +125,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
}
|
||||
|
||||
"stack_getbounds" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [stack] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
let stack = this.deref_pointer_as(stack, this.libc_ty_layout("stack_t"))?;
|
||||
|
||||
|
|
@ -140,6 +144,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
}
|
||||
|
||||
"pset_info" => {
|
||||
// FIXME: This does not have a direct test (#3179).
|
||||
let [pset, tpe, cpus, list] =
|
||||
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
// We do not need to handle the current process cpu mask, available_parallelism
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -6,7 +6,7 @@ use rustc_target::callconv::FnAbi;
|
|||
|
||||
use super::{
|
||||
ShiftOp, horizontal_bin_op, mpsadbw, packssdw, packsswb, packusdw, packuswb, permute, pmaddbw,
|
||||
pmulhrsw, psadbw, pshufb, psign, shift_simd_by_scalar,
|
||||
pmaddwd, pmulhrsw, psadbw, pshufb, psign, shift_simd_by_scalar,
|
||||
};
|
||||
use crate::*;
|
||||
|
||||
|
|
@ -232,33 +232,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
let [left, right] =
|
||||
this.check_shim_sig_lenient(abi, CanonAbi::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)?;
|
||||
|
||||
assert_eq!(left_len, right_len);
|
||||
assert_eq!(dest_len.strict_mul(2), left_len);
|
||||
|
||||
for i in 0..dest_len {
|
||||
let j1 = i.strict_mul(2);
|
||||
let left1 = this.read_scalar(&this.project_index(&left, j1)?)?.to_i16()?;
|
||||
let right1 = this.read_scalar(&this.project_index(&right, j1)?)?.to_i16()?;
|
||||
|
||||
let j2 = j1.strict_add(1);
|
||||
let left2 = this.read_scalar(&this.project_index(&left, j2)?)?.to_i16()?;
|
||||
let right2 = this.read_scalar(&this.project_index(&right, j2)?)?.to_i16()?;
|
||||
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
|
||||
// Multiplications are i16*i16->i32, which will not overflow.
|
||||
let mul1 = i32::from(left1).strict_mul(right1.into());
|
||||
let mul2 = i32::from(left2).strict_mul(right2.into());
|
||||
// However, this addition can overflow in the most extreme case
|
||||
// (-0x8000)*(-0x8000)+(-0x8000)*(-0x8000) = 0x80000000
|
||||
let res = mul1.wrapping_add(mul2);
|
||||
|
||||
this.write_scalar(Scalar::from_i32(res), &dest)?;
|
||||
}
|
||||
pmaddwd(this, left, right, dest)?;
|
||||
}
|
||||
_ => return interp_ok(EmulateItemResult::NotSupported),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use rustc_middle::ty::Ty;
|
|||
use rustc_span::Symbol;
|
||||
use rustc_target::callconv::FnAbi;
|
||||
|
||||
use super::{permute, pmaddbw, psadbw, pshufb};
|
||||
use super::{packssdw, packsswb, packusdw, packuswb, permute, pmaddbw, pmaddwd, psadbw, pshufb};
|
||||
use crate::*;
|
||||
|
||||
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
|
||||
|
|
@ -88,6 +88,15 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
|
||||
psadbw(this, left, right, dest)?
|
||||
}
|
||||
// Used to implement the _mm512_madd_epi16 function.
|
||||
"pmaddw.d.512" => {
|
||||
this.expect_target_feature_for_intrinsic(link_name, "avx512bw")?;
|
||||
|
||||
let [left, right] =
|
||||
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
|
||||
pmaddwd(this, left, right, dest)?;
|
||||
}
|
||||
// Used to implement the _mm512_maddubs_epi16 function.
|
||||
"pmaddubs.w.512" => {
|
||||
let [left, right] =
|
||||
|
|
@ -121,6 +130,38 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
|
||||
vpdpbusd(this, src, a, b, dest)?;
|
||||
}
|
||||
// Used to implement the _mm512_packs_epi16 function
|
||||
"packsswb.512" => {
|
||||
this.expect_target_feature_for_intrinsic(link_name, "avx512bw")?;
|
||||
|
||||
let [a, b] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
|
||||
packsswb(this, a, b, dest)?;
|
||||
}
|
||||
// Used to implement the _mm512_packus_epi16 function
|
||||
"packuswb.512" => {
|
||||
this.expect_target_feature_for_intrinsic(link_name, "avx512bw")?;
|
||||
|
||||
let [a, b] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
|
||||
packuswb(this, a, b, dest)?;
|
||||
}
|
||||
// Used to implement the _mm512_packs_epi32 function
|
||||
"packssdw.512" => {
|
||||
this.expect_target_feature_for_intrinsic(link_name, "avx512bw")?;
|
||||
|
||||
let [a, b] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
|
||||
packssdw(this, a, b, dest)?;
|
||||
}
|
||||
// Used to implement the _mm512_packus_epi32 function
|
||||
"packusdw.512" => {
|
||||
this.expect_target_feature_for_intrinsic(link_name, "avx512bw")?;
|
||||
|
||||
let [a, b] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
|
||||
|
||||
packusdw(this, a, b, dest)?;
|
||||
}
|
||||
_ => return interp_ok(EmulateItemResult::NotSupported),
|
||||
}
|
||||
interp_ok(EmulateItemResult::NeedsReturn)
|
||||
|
|
|
|||
|
|
@ -964,6 +964,52 @@ fn psadbw<'tcx>(
|
|||
interp_ok(())
|
||||
}
|
||||
|
||||
/// Multiply packed signed 16-bit integers in `left` and `right`, producing intermediate signed 32-bit integers.
|
||||
/// Horizontally add adjacent pairs of intermediate 32-bit integers, and pack the results in `dest`.
|
||||
///
|
||||
/// <https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_madd_epi16>
|
||||
/// <https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_madd_epi16>
|
||||
/// <https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm512_madd_epi16>
|
||||
fn pmaddwd<'tcx>(
|
||||
ecx: &mut crate::MiriInterpCx<'tcx>,
|
||||
left: &OpTy<'tcx>,
|
||||
right: &OpTy<'tcx>,
|
||||
dest: &MPlaceTy<'tcx>,
|
||||
) -> InterpResult<'tcx, ()> {
|
||||
let (left, left_len) = ecx.project_to_simd(left)?;
|
||||
let (right, right_len) = ecx.project_to_simd(right)?;
|
||||
let (dest, dest_len) = ecx.project_to_simd(dest)?;
|
||||
|
||||
// fn pmaddwd(a: i16x8, b: i16x8) -> i32x4;
|
||||
// fn pmaddwd(a: i16x16, b: i16x16) -> i32x8;
|
||||
// fn vpmaddwd(a: i16x32, b: i16x32) -> i32x16;
|
||||
assert_eq!(left_len, right_len);
|
||||
assert_eq!(dest_len.strict_mul(2), left_len);
|
||||
|
||||
for i in 0..dest_len {
|
||||
let j1 = i.strict_mul(2);
|
||||
let left1 = ecx.read_scalar(&ecx.project_index(&left, j1)?)?.to_i16()?;
|
||||
let right1 = ecx.read_scalar(&ecx.project_index(&right, j1)?)?.to_i16()?;
|
||||
|
||||
let j2 = j1.strict_add(1);
|
||||
let left2 = ecx.read_scalar(&ecx.project_index(&left, j2)?)?.to_i16()?;
|
||||
let right2 = ecx.read_scalar(&ecx.project_index(&right, j2)?)?.to_i16()?;
|
||||
|
||||
let dest = ecx.project_index(&dest, i)?;
|
||||
|
||||
// Multiplications are i16*i16->i32, which will not overflow.
|
||||
let mul1 = i32::from(left1).strict_mul(right1.into());
|
||||
let mul2 = i32::from(left2).strict_mul(right2.into());
|
||||
// However, this addition can overflow in the most extreme case
|
||||
// (-0x8000)*(-0x8000)+(-0x8000)*(-0x8000) = 0x80000000
|
||||
let res = mul1.wrapping_add(mul2);
|
||||
|
||||
ecx.write_scalar(Scalar::from_i32(res), &dest)?;
|
||||
}
|
||||
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
/// Multiplies packed 8-bit unsigned integers from `left` and packed
|
||||
/// signed 8-bit integers from `right` into 16-bit signed integers. Then,
|
||||
/// the saturating sum of the products with indices `2*i` and `2*i+1`
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc_target::callconv::FnAbi;
|
|||
|
||||
use super::{
|
||||
FloatBinOp, ShiftOp, bin_op_simd_float_all, bin_op_simd_float_first, convert_float_to_int,
|
||||
packssdw, packsswb, packuswb, psadbw, shift_simd_by_scalar,
|
||||
packssdw, packsswb, packuswb, pmaddwd, psadbw, shift_simd_by_scalar,
|
||||
};
|
||||
use crate::*;
|
||||
|
||||
|
|
@ -286,33 +286,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
let [left, right] =
|
||||
this.check_shim_sig_lenient(abi, CanonAbi::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)?;
|
||||
|
||||
assert_eq!(left_len, right_len);
|
||||
assert_eq!(dest_len.strict_mul(2), left_len);
|
||||
|
||||
for i in 0..dest_len {
|
||||
let j1 = i.strict_mul(2);
|
||||
let left1 = this.read_scalar(&this.project_index(&left, j1)?)?.to_i16()?;
|
||||
let right1 = this.read_scalar(&this.project_index(&right, j1)?)?.to_i16()?;
|
||||
|
||||
let j2 = j1.strict_add(1);
|
||||
let left2 = this.read_scalar(&this.project_index(&left, j2)?)?.to_i16()?;
|
||||
let right2 = this.read_scalar(&this.project_index(&right, j2)?)?.to_i16()?;
|
||||
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
|
||||
// Multiplications are i16*i16->i32, which will not overflow.
|
||||
let mul1 = i32::from(left1).strict_mul(right1.into());
|
||||
let mul2 = i32::from(left2).strict_mul(right2.into());
|
||||
// However, this addition can overflow in the most extreme case
|
||||
// (-0x8000)*(-0x8000)+(-0x8000)*(-0x8000) = 0x80000000
|
||||
let res = mul1.wrapping_add(mul2);
|
||||
|
||||
this.write_scalar(Scalar::from_i32(res), &dest)?;
|
||||
}
|
||||
pmaddwd(this, left, right, dest)?;
|
||||
}
|
||||
_ => return interp_ok(EmulateItemResult::NotSupported),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use windows_sys::Win32::System::Threading::{INFINITE, WaitForSingleObject};
|
|||
|
||||
// XXX HACK: This is how miri represents the handle for thread 0.
|
||||
// This value can be "legitimately" obtained by using `GetCurrentThread` with `DuplicateHandle`
|
||||
// but miri does not implement `DuplicateHandle` yet.
|
||||
// but miri does not implement `DuplicateHandle` yet. (FIXME: it does now.)
|
||||
const MAIN_THREAD: HANDLE = (2i32 << 29) as HANDLE;
|
||||
|
||||
fn main() {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ fn main() {
|
|||
#[cfg(not(target_os = "solaris"))]
|
||||
getrandom_01::getrandom(&mut data).unwrap();
|
||||
|
||||
// On Windows, getrandom 0.2 uses the wrong return type for BCryptGenRandom
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
getrandom_02::getrandom(&mut data).unwrap();
|
||||
|
||||
getrandom_03::fill(&mut data).unwrap();
|
||||
|
|
|
|||
13
src/tools/miri/tests/pass-dep/libc/close-std-streams.rs
Normal file
13
src/tools/miri/tests/pass-dep/libc/close-std-streams.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
//@ignore-target: windows # no libc
|
||||
//@ revisions: default null
|
||||
//@[null] compile-flags: -Zmiri-mute-stdout-stderr
|
||||
|
||||
fn main() {
|
||||
// This is std library UB, but that's not relevant since we're
|
||||
// only interacting with libc here.
|
||||
unsafe {
|
||||
libc::close(0);
|
||||
libc::close(1);
|
||||
libc::close(2);
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,10 @@ use std::mem::{size_of, size_of_val};
|
|||
|
||||
use libc::{cpu_set_t, sched_getaffinity, sched_setaffinity};
|
||||
|
||||
#[path = "../../utils/libc.rs"]
|
||||
mod libc_utils;
|
||||
use libc_utils::errno_check;
|
||||
|
||||
// If pid is zero, then the calling thread is used.
|
||||
const PID: i32 = 0;
|
||||
|
||||
|
|
@ -41,8 +45,7 @@ fn configure_unavailable_cpu() {
|
|||
// Safety: valid value for this type
|
||||
let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
|
||||
|
||||
let err = unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut cpuset) };
|
||||
assert_eq!(err, 0);
|
||||
errno_check(unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut cpuset) });
|
||||
|
||||
// by default, only available CPUs are configured
|
||||
for i in 0..cpu_count {
|
||||
|
|
@ -53,11 +56,9 @@ fn configure_unavailable_cpu() {
|
|||
// configure CPU that we don't have
|
||||
unsafe { libc::CPU_SET(cpu_count, &mut cpuset) };
|
||||
|
||||
let err = unsafe { sched_setaffinity(PID, size_of::<cpu_set_t>(), &cpuset) };
|
||||
assert_eq!(err, 0);
|
||||
errno_check(unsafe { sched_setaffinity(PID, size_of::<cpu_set_t>(), &cpuset) });
|
||||
|
||||
let err = unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut cpuset) };
|
||||
assert_eq!(err, 0);
|
||||
errno_check(unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut cpuset) });
|
||||
|
||||
// the CPU is not set because it is not available
|
||||
assert!(!unsafe { libc::CPU_ISSET(cpu_count, &cpuset) });
|
||||
|
|
@ -70,11 +71,11 @@ fn large_set() {
|
|||
// i.e. this has 2048 bits, twice the standard number
|
||||
let mut cpuset = [u64::MAX; 32];
|
||||
|
||||
let err = unsafe { sched_setaffinity(PID, size_of_val(&cpuset), cpuset.as_ptr().cast()) };
|
||||
assert_eq!(err, 0);
|
||||
errno_check(unsafe { sched_setaffinity(PID, size_of_val(&cpuset), cpuset.as_ptr().cast()) });
|
||||
|
||||
let err = unsafe { sched_getaffinity(PID, size_of_val(&cpuset), cpuset.as_mut_ptr().cast()) };
|
||||
assert_eq!(err, 0);
|
||||
errno_check(unsafe {
|
||||
sched_getaffinity(PID, size_of_val(&cpuset), cpuset.as_mut_ptr().cast())
|
||||
});
|
||||
}
|
||||
|
||||
fn get_small_cpu_mask() {
|
||||
|
|
@ -91,8 +92,7 @@ fn get_small_cpu_mask() {
|
|||
assert_eq!(std::io::Error::last_os_error().kind(), std::io::ErrorKind::InvalidInput);
|
||||
} else {
|
||||
// other whole multiples of the size of c_ulong works
|
||||
let err = unsafe { sched_getaffinity(PID, i, &mut cpuset) };
|
||||
assert_eq!(err, 0, "fail for {i}");
|
||||
errno_check(unsafe { sched_getaffinity(PID, i, &mut cpuset) });
|
||||
}
|
||||
|
||||
// anything else returns an error
|
||||
|
|
@ -107,8 +107,7 @@ fn get_small_cpu_mask() {
|
|||
fn set_small_cpu_mask() {
|
||||
let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
|
||||
|
||||
let err = unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut cpuset) };
|
||||
assert_eq!(err, 0);
|
||||
errno_check(unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut cpuset) });
|
||||
|
||||
// setting a mask of size 0 is invalid
|
||||
let err = unsafe { sched_setaffinity(PID, 0, &cpuset) };
|
||||
|
|
@ -122,8 +121,7 @@ fn set_small_cpu_mask() {
|
|||
if cfg!(target_endian = "little") { 1 } else { core::mem::size_of::<std::ffi::c_ulong>() };
|
||||
|
||||
for i in cpu_zero_included_length..24 {
|
||||
let err = unsafe { sched_setaffinity(PID, i, &cpuset) };
|
||||
assert_eq!(err, 0, "fail for {i}");
|
||||
errno_check(unsafe { sched_setaffinity(PID, i, &cpuset) });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -135,8 +133,7 @@ fn set_custom_cpu_mask() {
|
|||
let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
|
||||
|
||||
// at the start, thread 1 should be set
|
||||
let err = unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut cpuset) };
|
||||
assert_eq!(err, 0);
|
||||
errno_check(unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut cpuset) });
|
||||
assert!(unsafe { libc::CPU_ISSET(1, &cpuset) });
|
||||
|
||||
// make a valid mask
|
||||
|
|
@ -144,12 +141,10 @@ fn set_custom_cpu_mask() {
|
|||
unsafe { libc::CPU_SET(0, &mut cpuset) };
|
||||
|
||||
// giving a smaller mask is fine
|
||||
let err = unsafe { sched_setaffinity(PID, 8, &cpuset) };
|
||||
assert_eq!(err, 0);
|
||||
errno_check(unsafe { sched_setaffinity(PID, 8, &cpuset) });
|
||||
|
||||
// and actually disables other threads
|
||||
let err = unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut cpuset) };
|
||||
assert_eq!(err, 0);
|
||||
errno_check(unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut cpuset) });
|
||||
assert!(unsafe { !libc::CPU_ISSET(1, &cpuset) });
|
||||
|
||||
// it is important that we reset the cpu mask now for future tests
|
||||
|
|
@ -157,8 +152,7 @@ fn set_custom_cpu_mask() {
|
|||
unsafe { libc::CPU_SET(i, &mut cpuset) };
|
||||
}
|
||||
|
||||
let err = unsafe { sched_setaffinity(PID, size_of::<cpu_set_t>(), &cpuset) };
|
||||
assert_eq!(err, 0);
|
||||
errno_check(unsafe { sched_setaffinity(PID, size_of::<cpu_set_t>(), &cpuset) });
|
||||
}
|
||||
|
||||
fn parent_child() {
|
||||
|
|
@ -170,15 +164,13 @@ fn parent_child() {
|
|||
let mut parent_cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
|
||||
unsafe { libc::CPU_SET(0, &mut parent_cpuset) };
|
||||
|
||||
let err = unsafe { sched_setaffinity(PID, size_of::<cpu_set_t>(), &parent_cpuset) };
|
||||
assert_eq!(err, 0);
|
||||
errno_check(unsafe { sched_setaffinity(PID, size_of::<cpu_set_t>(), &parent_cpuset) });
|
||||
|
||||
std::thread::scope(|spawner| {
|
||||
spawner.spawn(|| {
|
||||
let mut cpuset: cpu_set_t = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
|
||||
|
||||
let err = unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut cpuset) };
|
||||
assert_eq!(err, 0);
|
||||
errno_check(unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut cpuset) });
|
||||
|
||||
// the child inherits its parent's set
|
||||
assert!(unsafe { libc::CPU_ISSET(0, &cpuset) });
|
||||
|
|
@ -189,8 +181,7 @@ fn parent_child() {
|
|||
});
|
||||
});
|
||||
|
||||
let err = unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut parent_cpuset) };
|
||||
assert_eq!(err, 0);
|
||||
errno_check(unsafe { sched_getaffinity(PID, size_of::<cpu_set_t>(), &mut parent_cpuset) });
|
||||
|
||||
// the parent's set should be unaffected
|
||||
assert!(unsafe { !libc::CPU_ISSET(1, &parent_cpuset) });
|
||||
|
|
@ -201,8 +192,7 @@ fn parent_child() {
|
|||
unsafe { libc::CPU_SET(i, &mut cpuset) };
|
||||
}
|
||||
|
||||
let err = unsafe { sched_setaffinity(PID, size_of::<cpu_set_t>(), &cpuset) };
|
||||
assert_eq!(err, 0);
|
||||
errno_check(unsafe { sched_setaffinity(PID, size_of::<cpu_set_t>(), &cpuset) });
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ use std::thread;
|
|||
|
||||
#[path = "../../utils/libc.rs"]
|
||||
mod libc_utils;
|
||||
use libc_utils::epoll::*;
|
||||
use libc_utils::*;
|
||||
|
||||
// This is a set of testcases for blocking epoll.
|
||||
|
||||
|
|
@ -19,48 +21,20 @@ fn main() {
|
|||
multiple_events_wake_multiple_threads();
|
||||
}
|
||||
|
||||
// Using `as` cast since `EPOLLET` wraps around
|
||||
const EPOLL_IN_OUT_ET: u32 = (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as _;
|
||||
|
||||
#[track_caller]
|
||||
fn check_epoll_wait<const N: usize>(
|
||||
epfd: i32,
|
||||
expected_notifications: &[(u32, u64)],
|
||||
timeout: i32,
|
||||
) {
|
||||
let epoll_event = libc::epoll_event { events: 0, u64: 0 };
|
||||
let mut array: [libc::epoll_event; N] = [epoll_event; N];
|
||||
let maxsize = N;
|
||||
let array_ptr = array.as_mut_ptr();
|
||||
let res = unsafe { libc::epoll_wait(epfd, array_ptr, maxsize.try_into().unwrap(), timeout) };
|
||||
if res < 0 {
|
||||
panic!("epoll_wait failed: {}", std::io::Error::last_os_error());
|
||||
}
|
||||
let got_notifications =
|
||||
unsafe { std::slice::from_raw_parts(array_ptr, res.try_into().unwrap()) };
|
||||
let got_notifications = got_notifications.iter().map(|e| (e.events, e.u64)).collect::<Vec<_>>();
|
||||
assert_eq!(got_notifications, expected_notifications, "got wrong notifications");
|
||||
}
|
||||
|
||||
// This test allows epoll_wait to block, then unblock without notification.
|
||||
fn test_epoll_block_without_notification() {
|
||||
// Create an epoll instance.
|
||||
let epfd = unsafe { libc::epoll_create1(0) };
|
||||
assert_ne!(epfd, -1);
|
||||
let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap();
|
||||
|
||||
// Create an eventfd instances.
|
||||
let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC;
|
||||
let fd = unsafe { libc::eventfd(0, flags) };
|
||||
let fd = errno_result(unsafe { libc::eventfd(0, flags) }).unwrap();
|
||||
|
||||
// Register eventfd with epoll.
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd, fd, libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
|
||||
// epoll_wait to clear notification.
|
||||
let expected_event = u32::try_from(libc::EPOLLOUT).unwrap();
|
||||
let expected_value = fd as u64;
|
||||
check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 0);
|
||||
check_epoll_wait::<1>(epfd, &[Ev { events: libc::EPOLLOUT, data: fd }], 0);
|
||||
|
||||
// This epoll wait blocks, and timeout without notification.
|
||||
check_epoll_wait::<1>(epfd, &[], 5);
|
||||
|
|
@ -69,102 +43,74 @@ fn test_epoll_block_without_notification() {
|
|||
// This test triggers notification and unblocks the epoll_wait before timeout.
|
||||
fn test_epoll_block_then_unblock() {
|
||||
// Create an epoll instance.
|
||||
let epfd = unsafe { libc::epoll_create1(0) };
|
||||
assert_ne!(epfd, -1);
|
||||
let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap();
|
||||
|
||||
// Create a socketpair instance.
|
||||
let mut fds = [-1, -1];
|
||||
let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
|
||||
assert_eq!(res, 0);
|
||||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
// Register one side of the socketpair with epoll.
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[0], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd, fds[0], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
|
||||
// epoll_wait to clear notification.
|
||||
let expected_event = u32::try_from(libc::EPOLLOUT).unwrap();
|
||||
let expected_value = fds[0] as u64;
|
||||
check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 0);
|
||||
check_epoll_wait::<1>(epfd, &[Ev { events: libc::EPOLLOUT, data: fds[0] }], 0);
|
||||
|
||||
// epoll_wait before triggering notification so it will block then get unblocked before timeout.
|
||||
let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap();
|
||||
let expected_value = fds[0] as u64;
|
||||
let thread1 = thread::spawn(move || {
|
||||
thread::yield_now();
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
write_all_from_slice(fds[1], b"abcde").unwrap();
|
||||
});
|
||||
check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 10);
|
||||
check_epoll_wait::<1>(epfd, &[Ev { events: libc::EPOLLIN | libc::EPOLLOUT, data: fds[0] }], 10);
|
||||
thread1.join().unwrap();
|
||||
}
|
||||
|
||||
// This test triggers a notification after epoll_wait times out.
|
||||
fn test_notification_after_timeout() {
|
||||
// Create an epoll instance.
|
||||
let epfd = unsafe { libc::epoll_create1(0) };
|
||||
assert_ne!(epfd, -1);
|
||||
let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap();
|
||||
|
||||
// Create a socketpair instance.
|
||||
let mut fds = [-1, -1];
|
||||
let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
|
||||
assert_eq!(res, 0);
|
||||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
// Register one side of the socketpair with epoll.
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[0], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd, fds[0], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
|
||||
// epoll_wait to clear notification.
|
||||
let expected_event = u32::try_from(libc::EPOLLOUT).unwrap();
|
||||
let expected_value = fds[0] as u64;
|
||||
check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 0);
|
||||
check_epoll_wait::<1>(epfd, &[Ev { events: libc::EPOLLOUT, data: fds[0] }], 0);
|
||||
|
||||
// epoll_wait timeouts without notification.
|
||||
check_epoll_wait::<1>(epfd, &[], 10);
|
||||
|
||||
// Trigger epoll notification after timeout.
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
write_all_from_slice(fds[1], b"abcde").unwrap();
|
||||
|
||||
// Check the result of the notification.
|
||||
let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap();
|
||||
let expected_value = fds[0] as u64;
|
||||
check_epoll_wait::<1>(epfd, &[(expected_event, expected_value)], 10);
|
||||
check_epoll_wait::<1>(epfd, &[Ev { events: libc::EPOLLIN | libc::EPOLLOUT, data: fds[0] }], 10);
|
||||
}
|
||||
|
||||
// This test shows a data_race before epoll had vector clocks added.
|
||||
fn test_epoll_race() {
|
||||
// Create an epoll instance.
|
||||
let epfd = unsafe { libc::epoll_create1(0) };
|
||||
assert_ne!(epfd, -1);
|
||||
let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap();
|
||||
|
||||
// Create an eventfd instance.
|
||||
let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC;
|
||||
let fd = unsafe { libc::eventfd(0, flags) };
|
||||
let fd = errno_result(unsafe { libc::eventfd(0, flags) }).unwrap();
|
||||
|
||||
// Register eventfd with the epoll instance.
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd, fd, libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
|
||||
static mut VAL: u8 = 0;
|
||||
let thread1 = thread::spawn(move || {
|
||||
// Write to the static mut variable.
|
||||
unsafe { VAL = 1 };
|
||||
// Write to the eventfd instance.
|
||||
let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes();
|
||||
let res = unsafe { libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8) };
|
||||
// write returns number of bytes written, which is always 8.
|
||||
assert_eq!(res, 8);
|
||||
write_all_from_slice(fd, &1_u64.to_ne_bytes()).unwrap();
|
||||
});
|
||||
thread::yield_now();
|
||||
// epoll_wait for the event to happen.
|
||||
let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap();
|
||||
let expected_value = u64::try_from(fd).unwrap();
|
||||
check_epoll_wait::<8>(epfd, &[(expected_event, expected_value)], -1);
|
||||
check_epoll_wait::<8>(epfd, &[Ev { events: (libc::EPOLLIN | libc::EPOLLOUT), data: fd }], -1);
|
||||
// Read from the static mut variable.
|
||||
#[allow(static_mut_refs)]
|
||||
unsafe {
|
||||
|
|
@ -177,35 +123,29 @@ fn test_epoll_race() {
|
|||
/// epoll it is blocked on.
|
||||
fn wakeup_on_new_interest() {
|
||||
// Create an epoll instance.
|
||||
let epfd = unsafe { libc::epoll_create1(0) };
|
||||
assert_ne!(epfd, -1);
|
||||
let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap();
|
||||
|
||||
// Create a socketpair instance.
|
||||
let mut fds = [-1, -1];
|
||||
let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
|
||||
assert_eq!(res, 0);
|
||||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
// Write to fd[0]
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
write_all_from_slice(fds[0], b"abcde").unwrap();
|
||||
|
||||
// Block a thread on the epoll instance.
|
||||
let t = std::thread::spawn(move || {
|
||||
let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap();
|
||||
let expected_value = u64::try_from(fds[1]).unwrap();
|
||||
check_epoll_wait::<8>(epfd, &[(expected_event, expected_value)], -1);
|
||||
check_epoll_wait::<8>(
|
||||
epfd,
|
||||
&[Ev { events: libc::EPOLLIN | libc::EPOLLOUT, data: fds[1] }],
|
||||
-1,
|
||||
);
|
||||
});
|
||||
// Ensure the thread is blocked.
|
||||
std::thread::yield_now();
|
||||
|
||||
// Register fd[1] with EPOLLIN|EPOLLOUT|EPOLLET|EPOLLRDHUP
|
||||
let mut ev = libc::epoll_event {
|
||||
events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET | libc::EPOLLRDHUP) as _,
|
||||
u64: u64::try_from(fds[1]).unwrap(),
|
||||
};
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[1], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd, fds[1], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET | libc::EPOLLRDHUP)
|
||||
.unwrap();
|
||||
|
||||
// This should wake up the thread.
|
||||
t.join().unwrap();
|
||||
|
|
@ -215,25 +155,21 @@ fn wakeup_on_new_interest() {
|
|||
/// to consume them all.
|
||||
fn multiple_events_wake_multiple_threads() {
|
||||
// Create an epoll instance.
|
||||
let epfd = unsafe { libc::epoll_create1(0) };
|
||||
assert_ne!(epfd, -1);
|
||||
let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap();
|
||||
|
||||
// Create an eventfd instance.
|
||||
let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC;
|
||||
let fd1 = unsafe { libc::eventfd(0, flags) };
|
||||
let fd1 = errno_result(unsafe { libc::eventfd(0, flags) }).unwrap();
|
||||
// Make a duplicate so that we have two file descriptors for the same file description.
|
||||
let fd2 = unsafe { libc::dup(fd1) };
|
||||
let fd2 = errno_result(unsafe { libc::dup(fd1) }).unwrap();
|
||||
|
||||
// Register both with epoll.
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd1 as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd1, &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd2 as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd2, &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd, fd1, libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
epoll_ctl_add(epfd, fd2, libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
|
||||
// Consume the initial events.
|
||||
let expected = [(libc::EPOLLOUT as u32, fd1 as u64), (libc::EPOLLOUT as u32, fd2 as u64)];
|
||||
let expected =
|
||||
[Ev { events: libc::EPOLLOUT, data: fd1 }, Ev { events: libc::EPOLLOUT, data: fd2 }];
|
||||
check_epoll_wait::<8>(epfd, &expected, -1);
|
||||
|
||||
// Block two threads on the epoll, both wanting to get just one event.
|
||||
|
|
@ -241,19 +177,19 @@ fn multiple_events_wake_multiple_threads() {
|
|||
let mut e = libc::epoll_event { events: 0, u64: 0 };
|
||||
let res = unsafe { libc::epoll_wait(epfd, &raw mut e, 1, -1) };
|
||||
assert!(res == 1);
|
||||
(e.events, e.u64)
|
||||
Ev { events: e.events.cast_signed(), data: e.u64.try_into().unwrap() }
|
||||
});
|
||||
let t2 = thread::spawn(move || {
|
||||
let mut e = libc::epoll_event { events: 0, u64: 0 };
|
||||
let res = unsafe { libc::epoll_wait(epfd, &raw mut e, 1, -1) };
|
||||
assert!(res == 1);
|
||||
(e.events, e.u64)
|
||||
Ev { events: e.events.cast_signed(), data: e.u64.try_into().unwrap() }
|
||||
});
|
||||
// Yield so both threads are waiting now.
|
||||
thread::yield_now();
|
||||
|
||||
// Trigger the eventfd. This triggers two events at once!
|
||||
libc_utils::write_all_from_slice(fd1, &0_u64.to_ne_bytes()).unwrap();
|
||||
write_all_from_slice(fd1, &0_u64.to_ne_bytes()).unwrap();
|
||||
|
||||
// Both threads should have been woken up so that both events can be consumed.
|
||||
let e1 = t1.join().unwrap();
|
||||
|
|
|
|||
|
|
@ -32,9 +32,6 @@ fn main() {
|
|||
test_issue_4374_reads();
|
||||
}
|
||||
|
||||
// Using `as` cast since `EPOLLET` wraps around
|
||||
const EPOLL_IN_OUT_ET: u32 = (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as _;
|
||||
|
||||
#[track_caller]
|
||||
fn check_epoll_wait<const N: usize>(epfd: i32, expected_notifications: &[(u32, u64)]) {
|
||||
let epoll_event = libc::epoll_event { events: 0, u64: 0 };
|
||||
|
|
@ -60,7 +57,7 @@ fn test_epoll_socketpair() {
|
|||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
// Write to fd[0]
|
||||
write_all_from_slice(fds[0], "abcde".as_bytes()).unwrap();
|
||||
write_all_from_slice(fds[0], b"abcde").unwrap();
|
||||
|
||||
// Register fd[1] with EPOLLIN|EPOLLOUT|EPOLLET|EPOLLRDHUP
|
||||
epoll_ctl_add(epfd, fds[1], EPOLLIN | EPOLLOUT | EPOLLET | EPOLLRDHUP).unwrap();
|
||||
|
|
@ -72,7 +69,7 @@ fn test_epoll_socketpair() {
|
|||
check_epoll_wait_noblock::<8>(epfd, &[]);
|
||||
|
||||
// Write some more to fd[0].
|
||||
write_all_from_slice(fds[0], "abcde".as_bytes()).unwrap();
|
||||
write_all_from_slice(fds[0], b"abcde").unwrap();
|
||||
|
||||
// This did not change the readiness of fd[1], so we should get no event.
|
||||
// However, Linux seems to always deliver spurious events to the peer on each write,
|
||||
|
|
@ -140,12 +137,15 @@ fn test_epoll_ctl_del() {
|
|||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
// Write to fd[0]
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let data = b"abcde".as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
|
||||
// Register fd[1] with EPOLLIN|EPOLLOUT|EPOLLET
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: u64::try_from(fds[1]).unwrap() };
|
||||
let mut ev = libc::epoll_event {
|
||||
events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as u32,
|
||||
u64: u64::try_from(fds[1]).unwrap(),
|
||||
};
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[1], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
|
||||
|
|
@ -168,16 +168,13 @@ fn test_two_epoll_instance() {
|
|||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
// Write to the socketpair.
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let data = b"abcde".as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
|
||||
// Register one side of the socketpair with EPOLLIN | EPOLLOUT | EPOLLET.
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: u64::try_from(fds[1]).unwrap() };
|
||||
let res = unsafe { libc::epoll_ctl(epfd1, libc::EPOLL_CTL_ADD, fds[1], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
let res = unsafe { libc::epoll_ctl(epfd2, libc::EPOLL_CTL_ADD, fds[1], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd1, fds[1], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
epoll_ctl_add(epfd2, fds[1], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
|
||||
// Notification should be received from both instance of epoll.
|
||||
let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap();
|
||||
|
|
@ -201,20 +198,23 @@ fn test_two_same_fd_in_same_epoll_instance() {
|
|||
assert_ne!(newfd, -1);
|
||||
|
||||
// Register both fd to the same epoll instance.
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: 5 as u64 };
|
||||
let mut ev = libc::epoll_event {
|
||||
events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).cast_unsigned(),
|
||||
u64: 5u64,
|
||||
};
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[1], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, newfd, &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
|
||||
// Write to the socketpair.
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let data = b"abcde".as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
|
||||
// Two notification should be received.
|
||||
let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap();
|
||||
let expected_value = 5 as u64;
|
||||
let expected_value = 5u64;
|
||||
check_epoll_wait::<8>(
|
||||
epfd,
|
||||
&[(expected_event, expected_value), (expected_event, expected_value)],
|
||||
|
|
@ -233,9 +233,7 @@ fn test_epoll_eventfd() {
|
|||
let epfd = errno_result(unsafe { libc::epoll_create1(0) }).unwrap();
|
||||
|
||||
// Register eventfd with EPOLLIN | EPOLLOUT | EPOLLET
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: u64::try_from(fd).unwrap() };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd, fd, libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
|
||||
// Check result from epoll_wait.
|
||||
let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap();
|
||||
|
|
@ -278,17 +276,13 @@ fn test_epoll_socketpair_both_sides() {
|
|||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
// Register both fd to the same epoll instance.
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[0], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[1] as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[1], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd, fds[0], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
epoll_ctl_add(epfd, fds[1], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
|
||||
// Write to fds[1].
|
||||
// (We do the write after the register here, unlike in `test_epoll_socketpair`, to ensure
|
||||
// we cover both orders in which this could be done.)
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let data = b"abcde".as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
|
||||
|
|
@ -307,7 +301,7 @@ fn test_epoll_socketpair_both_sides() {
|
|||
let res =
|
||||
unsafe { libc_utils::read_all(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
|
||||
assert_eq!(res, 5);
|
||||
assert_eq!(buf, "abcde".as_bytes());
|
||||
assert_eq!(buf, *b"abcde");
|
||||
|
||||
// The state of fds[1] does not change (was writable, is writable).
|
||||
// However, we force a spurious wakeup as the read buffer just got emptied.
|
||||
|
|
@ -326,9 +320,7 @@ fn test_closed_fd() {
|
|||
let fd = errno_result(unsafe { libc::eventfd(0, flags) }).unwrap();
|
||||
|
||||
// Register eventfd with EPOLLIN | EPOLLOUT | EPOLLET
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: u64::try_from(fd).unwrap() };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd, fd, libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
|
||||
// Write to the eventfd instance.
|
||||
let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes();
|
||||
|
|
@ -360,9 +352,7 @@ fn test_not_fully_closed_fd() {
|
|||
let newfd = errno_result(unsafe { libc::dup(fd) }).unwrap();
|
||||
|
||||
// Register eventfd with EPOLLIN | EPOLLOUT | EPOLLET
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: u64::try_from(fd).unwrap() };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd, fd, libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
|
||||
// Close the original fd that being used to register with epoll.
|
||||
errno_check(unsafe { libc::close(fd) });
|
||||
|
|
@ -402,7 +392,7 @@ fn test_event_overwrite() {
|
|||
|
||||
// Register eventfd with EPOLLIN | EPOLLOUT | EPOLLET
|
||||
let mut ev = libc::epoll_event {
|
||||
events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as _,
|
||||
events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).cast_unsigned(),
|
||||
u64: u64::try_from(fd).unwrap(),
|
||||
};
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) };
|
||||
|
|
@ -431,13 +421,13 @@ fn test_socketpair_read() {
|
|||
|
||||
// Register both fd to the same epoll instance.
|
||||
let mut ev = libc::epoll_event {
|
||||
events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as _,
|
||||
events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).cast_unsigned(),
|
||||
u64: fds[0] as u64,
|
||||
};
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[0], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
let mut ev = libc::epoll_event {
|
||||
events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET) as _,
|
||||
events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).cast_unsigned(),
|
||||
u64: fds[1] as u64,
|
||||
};
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[1], &mut ev) };
|
||||
|
|
@ -493,14 +483,14 @@ fn test_no_notification_for_unregister_flag() {
|
|||
|
||||
// Register fd[0] with EPOLLOUT|EPOLLET.
|
||||
let mut ev = libc::epoll_event {
|
||||
events: (libc::EPOLLOUT | libc::EPOLLET) as _,
|
||||
events: (libc::EPOLLOUT | libc::EPOLLET).cast_unsigned(),
|
||||
u64: u64::try_from(fds[0]).unwrap(),
|
||||
};
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[0], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
|
||||
// Write to fd[1].
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let data = b"abcde".as_ptr();
|
||||
let res: i32 = unsafe {
|
||||
libc_utils::write_all(fds[1], data as *const libc::c_void, 5).try_into().unwrap()
|
||||
};
|
||||
|
|
@ -534,7 +524,7 @@ fn test_socketpair_epollerr() {
|
|||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
// Write to fd[0]
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let data = b"abcde".as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
|
||||
|
|
@ -543,19 +533,15 @@ fn test_socketpair_epollerr() {
|
|||
errno_check(unsafe { libc::close(fds[1]) });
|
||||
|
||||
// Register fd[1] with EPOLLIN|EPOLLOUT|EPOLLET|EPOLLRDHUP
|
||||
let mut ev = libc::epoll_event {
|
||||
events: (libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET | libc::EPOLLRDHUP) as _,
|
||||
u64: u64::try_from(fds[1]).unwrap(),
|
||||
};
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[0], &mut ev) };
|
||||
assert_ne!(res, -1);
|
||||
epoll_ctl_add(epfd, fds[0], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET | libc::EPOLLRDHUP)
|
||||
.unwrap();
|
||||
|
||||
// Check result from epoll_wait.
|
||||
let expected_event = u32::try_from(
|
||||
libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLHUP | libc::EPOLLRDHUP | libc::EPOLLERR,
|
||||
)
|
||||
.unwrap();
|
||||
let expected_value = u64::try_from(fds[1]).unwrap();
|
||||
let expected_value = u64::try_from(fds[0]).unwrap();
|
||||
check_epoll_wait::<8>(epfd, &[(expected_event, expected_value)]);
|
||||
}
|
||||
|
||||
|
|
@ -570,12 +556,8 @@ fn test_epoll_lost_events() {
|
|||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
// Register both fd to the same epoll instance.
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[0], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[1] as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds[1], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd, fds[0], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
epoll_ctl_add(epfd, fds[1], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
|
||||
// Two notification should be received. But we only provide buffer for one event.
|
||||
let expected_event0 = u32::try_from(libc::EPOLLOUT).unwrap();
|
||||
|
|
@ -601,12 +583,8 @@ fn test_ready_list_fetching_logic() {
|
|||
let fd1 = errno_result(unsafe { libc::eventfd(0, flags) }).unwrap();
|
||||
|
||||
// Register both fd to the same epoll instance. At this point, both of them are on the ready list.
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd0 as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd0, &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fd1 as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd1, &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd, fd0, libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
epoll_ctl_add(epfd, fd1, libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
|
||||
// Close fd0 so the first entry in the ready list will be empty.
|
||||
errno_check(unsafe { libc::close(fd0) });
|
||||
|
|
@ -643,9 +621,7 @@ fn test_epoll_ctl_notification() {
|
|||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
// Register one side of the socketpair with epoll.
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd0, libc::EPOLL_CTL_ADD, fds[0], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd0, fds[0], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
|
||||
// epoll_wait to clear notification for epfd0.
|
||||
let expected_event = u32::try_from(libc::EPOLLOUT).unwrap();
|
||||
|
|
@ -657,9 +633,7 @@ fn test_epoll_ctl_notification() {
|
|||
assert_ne!(epfd1, -1);
|
||||
|
||||
// Register the same file description for epfd1.
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd1, libc::EPOLL_CTL_ADD, fds[0], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd1, fds[0], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
check_epoll_wait::<1>(epfd1, &[(expected_event, expected_value)]);
|
||||
|
||||
// Previously this epoll_wait will receive a notification, but we shouldn't return notification
|
||||
|
|
@ -683,7 +657,7 @@ fn test_issue_3858() {
|
|||
|
||||
// Register eventfd with EPOLLIN | EPOLLET.
|
||||
let mut ev = libc::epoll_event {
|
||||
events: (libc::EPOLLIN | libc::EPOLLET) as _,
|
||||
events: (libc::EPOLLIN | libc::EPOLLET).cast_unsigned(),
|
||||
u64: u64::try_from(fd).unwrap(),
|
||||
};
|
||||
let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) };
|
||||
|
|
@ -715,9 +689,7 @@ fn test_issue_4374() {
|
|||
assert_eq!(unsafe { libc::fcntl(fds[1], libc::F_SETFL, libc::O_NONBLOCK) }, 0);
|
||||
|
||||
// Register fds[0] with epoll while it is writable (but not readable).
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd0, libc::EPOLL_CTL_ADD, fds[0], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd0, fds[0], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
|
||||
// Fill up fds[0] so that it is not writable any more.
|
||||
let zeros = [0u8; 512];
|
||||
|
|
@ -747,16 +719,14 @@ fn test_issue_4374_reads() {
|
|||
assert_eq!(unsafe { libc::fcntl(fds[1], libc::F_SETFL, libc::O_NONBLOCK) }, 0);
|
||||
|
||||
// Write to fds[1] so that fds[0] becomes readable.
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let data = b"abcde".as_ptr();
|
||||
let res: i32 = unsafe {
|
||||
libc_utils::write_all(fds[1], data as *const libc::c_void, 5).try_into().unwrap()
|
||||
};
|
||||
assert_eq!(res, 5);
|
||||
|
||||
// Register fds[0] with epoll while it is readable.
|
||||
let mut ev = libc::epoll_event { events: EPOLL_IN_OUT_ET, u64: fds[0] as u64 };
|
||||
let res = unsafe { libc::epoll_ctl(epfd0, libc::EPOLL_CTL_ADD, fds[0], &mut ev) };
|
||||
assert_eq!(res, 0);
|
||||
epoll_ctl_add(epfd0, fds[0], libc::EPOLLIN | libc::EPOLLOUT | libc::EPOLLET).unwrap();
|
||||
|
||||
// Read fds[0] so it is no longer readable.
|
||||
let mut buf = [0u8; 512];
|
||||
|
|
|
|||
|
|
@ -4,11 +4,14 @@
|
|||
//@compile-flags: -Zmiri-disable-isolation
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::io::{Error, ErrorKind};
|
||||
use std::io::ErrorKind;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
#[path = "../../utils/libc.rs"]
|
||||
mod libc_utils;
|
||||
#[path = "../../utils/mod.rs"]
|
||||
mod utils;
|
||||
use libc_utils::errno_result;
|
||||
|
||||
fn main() {
|
||||
test_readlink();
|
||||
|
|
@ -31,44 +34,48 @@ fn test_readlink() {
|
|||
// Make the buf one byte larger than it needs to be,
|
||||
// and check that the last byte is not overwritten.
|
||||
let mut large_buf = vec![0xFF; expected_path.len() + 1];
|
||||
let res =
|
||||
unsafe { libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) };
|
||||
let res = errno_result(unsafe {
|
||||
libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len())
|
||||
})
|
||||
.unwrap();
|
||||
// Check that the resolved path was properly written into the buf.
|
||||
assert_eq!(&large_buf[..(large_buf.len() - 1)], expected_path);
|
||||
assert_eq!(large_buf.last(), Some(&0xFF));
|
||||
assert_eq!(res, large_buf.len() as isize - 1);
|
||||
assert_eq!(res, (large_buf.len() - 1) as isize);
|
||||
|
||||
// Test that the resolved path is truncated if the provided buffer
|
||||
// is too small.
|
||||
let mut small_buf = [0u8; 2];
|
||||
let res =
|
||||
unsafe { libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) };
|
||||
let res = errno_result(unsafe {
|
||||
libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len())
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(small_buf, &expected_path[..small_buf.len()]);
|
||||
assert_eq!(res, small_buf.len() as isize);
|
||||
|
||||
// Test that we report a proper error for a missing path.
|
||||
let res = unsafe {
|
||||
let err = errno_result(unsafe {
|
||||
libc::readlink(
|
||||
c"MIRI_MISSING_FILE_NAME".as_ptr(),
|
||||
small_buf.as_mut_ptr().cast(),
|
||||
small_buf.len(),
|
||||
)
|
||||
};
|
||||
assert_eq!(res, -1);
|
||||
assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound);
|
||||
})
|
||||
.unwrap_err();
|
||||
assert_eq!(err.kind(), ErrorKind::NotFound);
|
||||
}
|
||||
|
||||
fn test_nofollow_symlink() {
|
||||
let bytes = b"Hello, World!\n";
|
||||
let path = utils::prepare_with_content("test_nofollow_symlink_target.txt", bytes);
|
||||
let path = utils::prepare_with_content("test_nofollow_symlink_target.txt", b"Hello, World!\n");
|
||||
|
||||
let symlink_path = utils::prepare("test_nofollow_symlink.txt");
|
||||
std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
|
||||
|
||||
let symlink_cpath = CString::new(symlink_path.as_os_str().as_bytes()).unwrap();
|
||||
|
||||
let ret = unsafe { libc::open(symlink_cpath.as_ptr(), libc::O_NOFOLLOW | libc::O_CLOEXEC) };
|
||||
assert_eq!(ret, -1);
|
||||
let err = Error::last_os_error().raw_os_error().unwrap();
|
||||
assert_eq!(err, libc::ELOOP);
|
||||
let err = errno_result(unsafe {
|
||||
libc::open(symlink_cpath.as_ptr(), libc::O_NOFOLLOW | libc::O_CLOEXEC)
|
||||
})
|
||||
.unwrap_err();
|
||||
assert_eq!(err.raw_os_error(), Some(libc::ELOOP));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//@ignore-target: windows # File handling is not implemented yet
|
||||
//@ignore-target: windows # no libc
|
||||
//@compile-flags: -Zmiri-disable-isolation
|
||||
|
||||
#![feature(io_error_more)]
|
||||
|
|
@ -48,7 +48,6 @@ fn main() {
|
|||
test_nofollow_not_symlink();
|
||||
#[cfg(target_os = "macos")]
|
||||
test_ioctl();
|
||||
test_close_stdout();
|
||||
}
|
||||
|
||||
fn test_file_open_unix_allow_two_args() {
|
||||
|
|
@ -580,11 +579,3 @@ fn test_ioctl() {
|
|||
assert_eq!(libc::ioctl(fd, libc::FIOCLEX), 0);
|
||||
}
|
||||
}
|
||||
|
||||
fn test_close_stdout() {
|
||||
// This is std library UB, but that's not relevant since we're
|
||||
// only interacting with libc here.
|
||||
unsafe {
|
||||
libc::close(1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use std::thread;
|
|||
|
||||
#[path = "../../utils/libc.rs"]
|
||||
mod libc_utils;
|
||||
use libc_utils::*;
|
||||
|
||||
fn main() {
|
||||
test_socketpair();
|
||||
|
|
@ -21,139 +22,89 @@ fn main() {
|
|||
|
||||
fn test_socketpair() {
|
||||
let mut fds = [-1, -1];
|
||||
let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
|
||||
assert_eq!(res, 0);
|
||||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
// Read size == data available in buffer.
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
let mut buf: [u8; 5] = [0; 5];
|
||||
let res =
|
||||
unsafe { libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
|
||||
assert_eq!(res, 5);
|
||||
assert_eq!(buf, "abcde".as_bytes());
|
||||
let data = b"abcde";
|
||||
write_all_from_slice(fds[0], data).unwrap();
|
||||
let buf = read_all_into_array::<5>(fds[1]).unwrap();
|
||||
assert_eq!(&buf, data);
|
||||
|
||||
// Read size > data available in buffer.
|
||||
let data = "abc".as_bytes();
|
||||
let res = unsafe { libc_utils::write_all(fds[0], data.as_ptr() as *const libc::c_void, 3) };
|
||||
assert_eq!(res, 3);
|
||||
let data = b"abc";
|
||||
write_all_from_slice(fds[0], data).unwrap();
|
||||
let mut buf2: [u8; 5] = [0; 5];
|
||||
let res = unsafe { libc::read(fds[1], buf2.as_mut_ptr().cast(), buf2.len() as libc::size_t) };
|
||||
assert!(res > 0 && res <= 3);
|
||||
let res = res as usize;
|
||||
assert_eq!(buf2[..res], data[..res]);
|
||||
if res < 3 {
|
||||
// Drain the rest from the read end.
|
||||
let res = unsafe { libc_utils::read_all(fds[1], buf2[res..].as_mut_ptr().cast(), 3 - res) };
|
||||
assert!(res > 0);
|
||||
}
|
||||
let (read, rest) = read_into_slice(fds[1], &mut buf2).unwrap();
|
||||
assert_eq!(read[..], data[..read.len()]);
|
||||
// Write 2 more bytes so we can exactly fill the `rest`.
|
||||
write_all_from_slice(fds[0], b"12").unwrap();
|
||||
read_all_into_slice(fds[1], rest).unwrap();
|
||||
|
||||
// Test read and write from another direction.
|
||||
// Read size == data available in buffer.
|
||||
let data = "12345".as_bytes().as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
let mut buf3: [u8; 5] = [0; 5];
|
||||
let res = unsafe {
|
||||
libc_utils::read_all(fds[0], buf3.as_mut_ptr().cast(), buf3.len() as libc::size_t)
|
||||
};
|
||||
assert_eq!(res, 5);
|
||||
assert_eq!(buf3, "12345".as_bytes());
|
||||
let data = b"12345";
|
||||
write_all_from_slice(fds[1], data).unwrap();
|
||||
let buf3 = read_all_into_array::<5>(fds[0]).unwrap();
|
||||
assert_eq!(&buf3, data);
|
||||
|
||||
// Read size > data available in buffer.
|
||||
let data = "123".as_bytes();
|
||||
let res = unsafe { libc_utils::write_all(fds[1], data.as_ptr() as *const libc::c_void, 3) };
|
||||
assert_eq!(res, 3);
|
||||
let data = b"123";
|
||||
write_all_from_slice(fds[1], data).unwrap();
|
||||
let mut buf4: [u8; 5] = [0; 5];
|
||||
let res = unsafe { libc::read(fds[0], buf4.as_mut_ptr().cast(), buf4.len() as libc::size_t) };
|
||||
assert!(res > 0 && res <= 3);
|
||||
let res = res as usize;
|
||||
assert_eq!(buf4[..res], data[..res]);
|
||||
if res < 3 {
|
||||
// Drain the rest from the read end.
|
||||
let res = unsafe { libc_utils::read_all(fds[0], buf4[res..].as_mut_ptr().cast(), 3 - res) };
|
||||
assert!(res > 0);
|
||||
}
|
||||
let (read, rest) = read_into_slice(fds[0], &mut buf4).unwrap();
|
||||
assert_eq!(read[..], data[..read.len()]);
|
||||
// Write 2 more bytes so we can exactly fill the `rest`.
|
||||
write_all_from_slice(fds[1], b"12").unwrap();
|
||||
read_all_into_slice(fds[0], rest).unwrap();
|
||||
|
||||
// Test when happens when we close one end, with some data in the buffer.
|
||||
let res = unsafe { libc_utils::write_all(fds[0], data.as_ptr() as *const libc::c_void, 3) };
|
||||
assert_eq!(res, 3);
|
||||
unsafe { libc::close(fds[0]) };
|
||||
write_all_from_slice(fds[0], data).unwrap();
|
||||
errno_check(unsafe { libc::close(fds[0]) });
|
||||
// Reading the other end should return that data, then EOF.
|
||||
let mut buf: [u8; 5] = [0; 5];
|
||||
let res =
|
||||
unsafe { libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
|
||||
assert_eq!(res, 3);
|
||||
assert_eq!(&buf[0..3], "123".as_bytes());
|
||||
let res =
|
||||
unsafe { libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
|
||||
assert_eq!(res, 0); // 0-sized read: EOF.
|
||||
let (res, _) = read_until_eof_into_slice(fds[1], &mut buf).unwrap();
|
||||
assert_eq!(res, data);
|
||||
// Writing the other end should emit EPIPE.
|
||||
let res = unsafe { libc_utils::write_all(fds[1], data.as_ptr() as *const libc::c_void, 1) };
|
||||
assert_eq!(res, -1);
|
||||
assert_eq!(std::io::Error::last_os_error().raw_os_error(), Some(libc::EPIPE));
|
||||
let err = write_all_from_slice(fds[1], &mut buf).unwrap_err();
|
||||
assert_eq!(err.raw_os_error(), Some(libc::EPIPE));
|
||||
}
|
||||
|
||||
fn test_socketpair_threaded() {
|
||||
let mut fds = [-1, -1];
|
||||
let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
|
||||
assert_eq!(res, 0);
|
||||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
let thread1 = thread::spawn(move || {
|
||||
let mut buf: [u8; 5] = [0; 5];
|
||||
let res: i64 = unsafe {
|
||||
libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
|
||||
.try_into()
|
||||
.unwrap()
|
||||
};
|
||||
assert_eq!(res, 5);
|
||||
assert_eq!(buf, "abcde".as_bytes());
|
||||
let buf = read_all_into_array::<5>(fds[1]).unwrap();
|
||||
assert_eq!(&buf, b"abcde");
|
||||
});
|
||||
thread::yield_now();
|
||||
let data = "abcde".as_bytes().as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
write_all_from_slice(fds[0], b"abcde").unwrap();
|
||||
thread1.join().unwrap();
|
||||
|
||||
// Read and write from different direction
|
||||
let thread2 = thread::spawn(move || {
|
||||
thread::yield_now();
|
||||
let data = "12345".as_bytes().as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[1], data as *const libc::c_void, 5) };
|
||||
assert_eq!(res, 5);
|
||||
write_all_from_slice(fds[1], b"12345").unwrap();
|
||||
});
|
||||
let mut buf: [u8; 5] = [0; 5];
|
||||
let res =
|
||||
unsafe { libc_utils::read_all(fds[0], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
|
||||
assert_eq!(res, 5);
|
||||
assert_eq!(buf, "12345".as_bytes());
|
||||
let buf = read_all_into_array::<5>(fds[0]).unwrap();
|
||||
assert_eq!(&buf, b"12345");
|
||||
thread2.join().unwrap();
|
||||
}
|
||||
|
||||
fn test_race() {
|
||||
static mut VAL: u8 = 0;
|
||||
let mut fds = [-1, -1];
|
||||
let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
|
||||
assert_eq!(res, 0);
|
||||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
let thread1 = thread::spawn(move || {
|
||||
let mut buf: [u8; 1] = [0; 1];
|
||||
// write() from the main thread will occur before the read() here
|
||||
// because preemption is disabled and the main thread yields after write().
|
||||
let res: i32 = unsafe {
|
||||
libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
|
||||
.try_into()
|
||||
.unwrap()
|
||||
};
|
||||
assert_eq!(res, 1);
|
||||
assert_eq!(buf, "a".as_bytes());
|
||||
let buf = read_all_into_array::<1>(fds[1]).unwrap();
|
||||
assert_eq!(&buf, b"a");
|
||||
// The read above establishes a happens-before so it is now safe to access this global variable.
|
||||
unsafe { assert_eq!(VAL, 1) };
|
||||
});
|
||||
unsafe { VAL = 1 };
|
||||
let data = "a".as_bytes().as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 1) };
|
||||
assert_eq!(res, 1);
|
||||
write_all_from_slice(fds[0], b"a").unwrap();
|
||||
thread::yield_now();
|
||||
thread1.join().unwrap();
|
||||
}
|
||||
|
|
@ -161,22 +112,15 @@ fn test_race() {
|
|||
// Test the behaviour of a socketpair getting blocked on read and subsequently unblocked.
|
||||
fn test_blocking_read() {
|
||||
let mut fds = [-1, -1];
|
||||
let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
|
||||
assert_eq!(res, 0);
|
||||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
let thread1 = thread::spawn(move || {
|
||||
// Let this thread block on read.
|
||||
let mut buf: [u8; 3] = [0; 3];
|
||||
let res = unsafe {
|
||||
libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
|
||||
};
|
||||
assert_eq!(res, 3);
|
||||
assert_eq!(&buf, "abc".as_bytes());
|
||||
let buf = read_all_into_array::<3>(fds[1]).unwrap();
|
||||
assert_eq!(&buf, b"abc");
|
||||
});
|
||||
let thread2 = thread::spawn(move || {
|
||||
// Unblock thread1 by doing writing something.
|
||||
let data = "abc".as_bytes().as_ptr();
|
||||
let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 3) };
|
||||
assert_eq!(res, 3);
|
||||
write_all_from_slice(fds[0], b"abc").unwrap();
|
||||
});
|
||||
thread1.join().unwrap();
|
||||
thread2.join().unwrap();
|
||||
|
|
@ -185,26 +129,17 @@ fn test_blocking_read() {
|
|||
// Test the behaviour of a socketpair getting blocked on write and subsequently unblocked.
|
||||
fn test_blocking_write() {
|
||||
let mut fds = [-1, -1];
|
||||
let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
|
||||
assert_eq!(res, 0);
|
||||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
let arr1: [u8; 0x34000] = [1; 0x34000];
|
||||
// Exhaust the space in the buffer so the subsequent write will block.
|
||||
let res =
|
||||
unsafe { libc_utils::write_all(fds[0], arr1.as_ptr() as *const libc::c_void, arr1.len()) };
|
||||
assert_eq!(res, 0x34000);
|
||||
write_all_from_slice(fds[0], &arr1).unwrap();
|
||||
let thread1 = thread::spawn(move || {
|
||||
let data = "abc".as_bytes().as_ptr();
|
||||
// The write below will be blocked because the buffer is already full.
|
||||
let res = unsafe { libc_utils::write_all(fds[0], data as *const libc::c_void, 3) };
|
||||
assert_eq!(res, 3);
|
||||
write_all_from_slice(fds[0], b"abc").unwrap();
|
||||
});
|
||||
let thread2 = thread::spawn(move || {
|
||||
// Unblock thread1 by freeing up some space.
|
||||
let mut buf: [u8; 3] = [0; 3];
|
||||
let res = unsafe {
|
||||
libc_utils::read_all(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t)
|
||||
};
|
||||
assert_eq!(res, 3);
|
||||
let buf = read_all_into_array::<3>(fds[1]).unwrap();
|
||||
assert_eq!(buf, [1, 1, 1]);
|
||||
});
|
||||
thread1.join().unwrap();
|
||||
|
|
@ -215,30 +150,25 @@ fn test_blocking_write() {
|
|||
fn test_socketpair_setfl_getfl() {
|
||||
// Initialise socketpair fds.
|
||||
let mut fds = [-1, -1];
|
||||
let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
|
||||
assert_eq!(res, 0);
|
||||
errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) });
|
||||
|
||||
// Test if both sides have O_RDWR.
|
||||
let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) };
|
||||
assert_eq!(res, libc::O_RDWR);
|
||||
let res = unsafe { libc::fcntl(fds[1], libc::F_GETFL) };
|
||||
assert_eq!(res, libc::O_RDWR);
|
||||
assert_eq!(errno_result(unsafe { libc::fcntl(fds[0], libc::F_GETFL) }).unwrap(), libc::O_RDWR);
|
||||
assert_eq!(errno_result(unsafe { libc::fcntl(fds[1], libc::F_GETFL) }).unwrap(), libc::O_RDWR);
|
||||
|
||||
// Add the O_NONBLOCK flag with F_SETFL.
|
||||
let res = unsafe { libc::fcntl(fds[0], libc::F_SETFL, libc::O_NONBLOCK) };
|
||||
assert_eq!(res, 0);
|
||||
errno_check(unsafe { libc::fcntl(fds[0], libc::F_SETFL, libc::O_NONBLOCK) });
|
||||
|
||||
// Test if the O_NONBLOCK flag is successfully added.
|
||||
let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) };
|
||||
assert_eq!(res, libc::O_RDWR | libc::O_NONBLOCK);
|
||||
assert_eq!(
|
||||
errno_result(unsafe { libc::fcntl(fds[0], libc::F_GETFL) }).unwrap(),
|
||||
libc::O_RDWR | libc::O_NONBLOCK
|
||||
);
|
||||
|
||||
// The other side remains unchanged.
|
||||
let res = unsafe { libc::fcntl(fds[1], libc::F_GETFL) };
|
||||
assert_eq!(res, libc::O_RDWR);
|
||||
assert_eq!(errno_result(unsafe { libc::fcntl(fds[1], libc::F_GETFL) }).unwrap(), libc::O_RDWR);
|
||||
|
||||
// Test if O_NONBLOCK flag can be unset.
|
||||
let res = unsafe { libc::fcntl(fds[0], libc::F_SETFL, 0) };
|
||||
assert_eq!(res, 0);
|
||||
let res = unsafe { libc::fcntl(fds[0], libc::F_GETFL) };
|
||||
assert_eq!(res, libc::O_RDWR);
|
||||
errno_check(unsafe { libc::fcntl(fds[0], libc::F_SETFL, 0) });
|
||||
assert_eq!(errno_result(unsafe { libc::fcntl(fds[0], libc::F_GETFL) }).unwrap(), libc::O_RDWR);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
//@ignore-target: windows # no libc time APIs on Windows
|
||||
//@compile-flags: -Zmiri-disable-isolation
|
||||
|
||||
#[path = "../../utils/libc.rs"]
|
||||
mod libc_utils;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{env, mem, ptr};
|
||||
|
||||
use libc_utils::errno_check;
|
||||
|
||||
fn main() {
|
||||
test_clocks();
|
||||
test_posix_gettimeofday();
|
||||
|
|
@ -39,30 +44,23 @@ fn main() {
|
|||
/// Tests whether clock support exists at all
|
||||
fn test_clocks() {
|
||||
let mut tp = mem::MaybeUninit::<libc::timespec>::uninit();
|
||||
let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) };
|
||||
assert_eq!(is_error, 0);
|
||||
let is_error = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, tp.as_mut_ptr()) };
|
||||
assert_eq!(is_error, 0);
|
||||
errno_check(unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) });
|
||||
errno_check(unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, tp.as_mut_ptr()) });
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "android"))]
|
||||
{
|
||||
let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME_COARSE, tp.as_mut_ptr()) };
|
||||
assert_eq!(is_error, 0);
|
||||
let is_error =
|
||||
unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr()) };
|
||||
assert_eq!(is_error, 0);
|
||||
errno_check(unsafe { libc::clock_gettime(libc::CLOCK_REALTIME_COARSE, tp.as_mut_ptr()) });
|
||||
errno_check(unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr()) });
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
let is_error = unsafe { libc::clock_gettime(libc::CLOCK_UPTIME_RAW, tp.as_mut_ptr()) };
|
||||
assert_eq!(is_error, 0);
|
||||
errno_check(unsafe { libc::clock_gettime(libc::CLOCK_UPTIME_RAW, tp.as_mut_ptr()) });
|
||||
}
|
||||
}
|
||||
|
||||
fn test_posix_gettimeofday() {
|
||||
let mut tp = mem::MaybeUninit::<libc::timeval>::uninit();
|
||||
let tz = ptr::null_mut::<libc::timezone>();
|
||||
let is_error = unsafe { libc::gettimeofday(tp.as_mut_ptr(), tz.cast()) };
|
||||
assert_eq!(is_error, 0);
|
||||
errno_check(unsafe { libc::gettimeofday(tp.as_mut_ptr(), tz.cast()) });
|
||||
let tv = unsafe { tp.assume_init() };
|
||||
assert!(tv.tv_sec > 0);
|
||||
assert!(tv.tv_usec >= 0); // Theoretically this could be 0.
|
||||
|
|
@ -334,15 +332,13 @@ fn test_nanosleep() {
|
|||
let start_test_sleep = Instant::now();
|
||||
let duration_zero = libc::timespec { tv_sec: 0, tv_nsec: 0 };
|
||||
let remainder = ptr::null_mut::<libc::timespec>();
|
||||
let is_error = unsafe { libc::nanosleep(&duration_zero, remainder) };
|
||||
assert_eq!(is_error, 0);
|
||||
errno_check(unsafe { libc::nanosleep(&duration_zero, remainder) });
|
||||
assert!(start_test_sleep.elapsed() < Duration::from_millis(100));
|
||||
|
||||
let start_test_sleep = Instant::now();
|
||||
let duration_100_millis = libc::timespec { tv_sec: 0, tv_nsec: 1_000_000_000 / 10 };
|
||||
let remainder = ptr::null_mut::<libc::timespec>();
|
||||
let is_error = unsafe { libc::nanosleep(&duration_100_millis, remainder) };
|
||||
assert_eq!(is_error, 0);
|
||||
errno_check(unsafe { libc::nanosleep(&duration_100_millis, remainder) });
|
||||
assert!(start_test_sleep.elapsed() > Duration::from_millis(100));
|
||||
}
|
||||
|
||||
|
|
@ -371,8 +367,7 @@ mod test_clock_nanosleep {
|
|||
/// Helper function to get the current time for testing relative sleeps
|
||||
fn timespec_now(clock: libc::clockid_t) -> libc::timespec {
|
||||
let mut timespec = mem::MaybeUninit::<libc::timespec>::uninit();
|
||||
let is_error = unsafe { libc::clock_gettime(clock, timespec.as_mut_ptr()) };
|
||||
assert_eq!(is_error, 0);
|
||||
errno_check(unsafe { libc::clock_gettime(clock, timespec.as_mut_ptr()) });
|
||||
unsafe { timespec.assume_init() }
|
||||
}
|
||||
|
||||
|
|
@ -380,7 +375,7 @@ mod test_clock_nanosleep {
|
|||
let start_test_sleep = Instant::now();
|
||||
let before_start = libc::timespec { tv_sec: 0, tv_nsec: 0 };
|
||||
let remainder = ptr::null_mut::<libc::timespec>();
|
||||
let error = unsafe {
|
||||
errno_check(unsafe {
|
||||
// this will not sleep since unix time zero is in the past
|
||||
libc::clock_nanosleep(
|
||||
libc::CLOCK_MONOTONIC,
|
||||
|
|
@ -388,22 +383,20 @@ mod test_clock_nanosleep {
|
|||
&before_start,
|
||||
remainder,
|
||||
)
|
||||
};
|
||||
assert_eq!(error, 0);
|
||||
});
|
||||
assert!(start_test_sleep.elapsed() < Duration::from_millis(100));
|
||||
|
||||
let start_test_sleep = Instant::now();
|
||||
let hunderd_millis_after_start = add_100_millis(timespec_now(libc::CLOCK_MONOTONIC));
|
||||
let remainder = ptr::null_mut::<libc::timespec>();
|
||||
let error = unsafe {
|
||||
errno_check(unsafe {
|
||||
libc::clock_nanosleep(
|
||||
libc::CLOCK_MONOTONIC,
|
||||
libc::TIMER_ABSTIME,
|
||||
&hunderd_millis_after_start,
|
||||
remainder,
|
||||
)
|
||||
};
|
||||
assert_eq!(error, 0);
|
||||
});
|
||||
assert!(start_test_sleep.elapsed() > Duration::from_millis(100));
|
||||
}
|
||||
|
||||
|
|
@ -413,19 +406,17 @@ mod test_clock_nanosleep {
|
|||
let start_test_sleep = Instant::now();
|
||||
let duration_zero = libc::timespec { tv_sec: 0, tv_nsec: 0 };
|
||||
let remainder = ptr::null_mut::<libc::timespec>();
|
||||
let error = unsafe {
|
||||
errno_check(unsafe {
|
||||
libc::clock_nanosleep(libc::CLOCK_MONOTONIC, NO_FLAGS, &duration_zero, remainder)
|
||||
};
|
||||
assert_eq!(error, 0);
|
||||
});
|
||||
assert!(start_test_sleep.elapsed() < Duration::from_millis(100));
|
||||
|
||||
let start_test_sleep = Instant::now();
|
||||
let duration_100_millis = libc::timespec { tv_sec: 0, tv_nsec: 1_000_000_000 / 10 };
|
||||
let remainder = ptr::null_mut::<libc::timespec>();
|
||||
let error = unsafe {
|
||||
errno_check(unsafe {
|
||||
libc::clock_nanosleep(libc::CLOCK_MONOTONIC, NO_FLAGS, &duration_100_millis, remainder)
|
||||
};
|
||||
assert_eq!(error, 0);
|
||||
});
|
||||
assert!(start_test_sleep.elapsed() > Duration::from_millis(100));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
//@compile-flags: -Cpanic=abort
|
||||
//@ignore-target: windows # no-std not supported on Windows
|
||||
|
||||
#[path = "../../utils/mod.no_std.rs"]
|
||||
mod utils;
|
||||
|
||||
extern "Rust" fn thread_start(_null: *mut ()) {
|
||||
unsafe {
|
||||
utils::miri_spin_loop();
|
||||
utils::miri_spin_loop();
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
unsafe {
|
||||
let thread_id = utils::miri_thread_spawn(thread_start, core::ptr::null_mut());
|
||||
assert_eq!(utils::miri_thread_join(thread_id), true);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic_handler(_: &core::panic::PanicInfo) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
|
@ -6,17 +6,15 @@
|
|||
// windows linker section, we can run this test on windows again.
|
||||
//@ignore-target: windows # no-std not supported on Windows
|
||||
|
||||
extern "Rust" {
|
||||
fn miri_alloc(size: usize, align: usize) -> *mut u8;
|
||||
fn miri_dealloc(ptr: *mut u8, size: usize, align: usize);
|
||||
}
|
||||
#[path = "../utils/mod.no_std.rs"]
|
||||
mod utils;
|
||||
|
||||
#[no_mangle]
|
||||
fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
unsafe {
|
||||
let ptr = miri_alloc(123, 1);
|
||||
let ptr = utils::miri_alloc(123, 1);
|
||||
core::ptr::write_bytes(ptr, 0u8, 123);
|
||||
miri_dealloc(ptr, 123, 1);
|
||||
utils::miri_dealloc(ptr, 123, 1);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// We're testing x86 target specific features
|
||||
//@only-target: x86_64 i686
|
||||
//@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq,+avx512vnni
|
||||
//@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512bitalg,+avx512vpopcntdq,+avx512vnni
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
use std::arch::x86::*;
|
||||
|
|
@ -11,12 +11,14 @@ use std::mem::transmute;
|
|||
fn main() {
|
||||
assert!(is_x86_feature_detected!("avx512f"));
|
||||
assert!(is_x86_feature_detected!("avx512vl"));
|
||||
assert!(is_x86_feature_detected!("avx512bw"));
|
||||
assert!(is_x86_feature_detected!("avx512bitalg"));
|
||||
assert!(is_x86_feature_detected!("avx512vpopcntdq"));
|
||||
assert!(is_x86_feature_detected!("avx512vnni"));
|
||||
|
||||
unsafe {
|
||||
test_avx512();
|
||||
test_avx512bw();
|
||||
test_avx512bitalg();
|
||||
test_avx512vpopcntdq();
|
||||
test_avx512ternarylogic();
|
||||
|
|
@ -100,6 +102,77 @@ unsafe fn test_avx512() {
|
|||
}
|
||||
test_mm512_maddubs_epi16();
|
||||
|
||||
#[target_feature(enable = "avx512bw")]
|
||||
unsafe fn test_mm512_madd_epi16() {
|
||||
// Input pairs
|
||||
//
|
||||
// - `i16::MIN * i16::MIN + i16::MIN * i16::MIN`: the 32-bit addition overflows
|
||||
// - `i16::MAX * i16::MAX + i16::MAX * i16::MAX`: check that widening happens before
|
||||
// arithmetic
|
||||
// - `i16::MIN * i16::MAX + i16::MAX * i16::MIN`: check that large negative values are
|
||||
// handled correctly
|
||||
// - `3 * 1 + 4 * 2`: A sanity check, the result should be 14.
|
||||
|
||||
#[rustfmt::skip]
|
||||
let a = _mm512_set_epi16(
|
||||
i16::MIN, i16::MIN,
|
||||
i16::MAX, i16::MAX,
|
||||
i16::MIN, i16::MAX,
|
||||
3, 1,
|
||||
|
||||
i16::MIN, i16::MIN,
|
||||
i16::MAX, i16::MAX,
|
||||
i16::MIN, i16::MAX,
|
||||
3, 1,
|
||||
|
||||
i16::MIN, i16::MIN,
|
||||
i16::MAX, i16::MAX,
|
||||
i16::MIN, i16::MAX,
|
||||
3, 1,
|
||||
|
||||
i16::MIN, i16::MIN,
|
||||
i16::MAX, i16::MAX,
|
||||
i16::MIN, i16::MAX,
|
||||
3, 1,
|
||||
);
|
||||
|
||||
#[rustfmt::skip]
|
||||
let b = _mm512_set_epi16(
|
||||
i16::MIN, i16::MIN,
|
||||
i16::MAX, i16::MAX,
|
||||
i16::MAX, i16::MIN,
|
||||
4, 2,
|
||||
|
||||
i16::MIN, i16::MIN,
|
||||
i16::MAX, i16::MAX,
|
||||
i16::MAX, i16::MIN,
|
||||
4, 2,
|
||||
|
||||
i16::MIN, i16::MIN,
|
||||
i16::MAX, i16::MAX,
|
||||
i16::MAX, i16::MIN,
|
||||
4, 2,
|
||||
|
||||
i16::MIN, i16::MIN,
|
||||
i16::MAX, i16::MAX,
|
||||
i16::MAX, i16::MIN,
|
||||
4, 2,
|
||||
);
|
||||
|
||||
let r = _mm512_madd_epi16(a, b);
|
||||
|
||||
#[rustfmt::skip]
|
||||
let e = _mm512_set_epi32(
|
||||
i32::MIN, 2_147_352_578, -2_147_418_112, 14,
|
||||
i32::MIN, 2_147_352_578, -2_147_418_112, 14,
|
||||
i32::MIN, 2_147_352_578, -2_147_418_112, 14,
|
||||
i32::MIN, 2_147_352_578, -2_147_418_112, 14,
|
||||
);
|
||||
|
||||
assert_eq_m512i(r, e);
|
||||
}
|
||||
test_mm512_madd_epi16();
|
||||
|
||||
#[target_feature(enable = "avx512f")]
|
||||
unsafe fn test_mm512_permutexvar_epi32() {
|
||||
let a = _mm512_set_epi32(
|
||||
|
|
@ -508,9 +581,133 @@ unsafe fn test_avx512vnni() {
|
|||
test_mm512_dpbusd_epi32();
|
||||
}
|
||||
|
||||
#[target_feature(enable = "avx512bw")]
|
||||
unsafe fn test_avx512bw() {
|
||||
#[target_feature(enable = "avx512bw")]
|
||||
unsafe fn test_mm512_packs_epi16() {
|
||||
let a = _mm512_set1_epi16(120);
|
||||
|
||||
// Because `packs` instructions do signed saturation, we expect
|
||||
// that any value over `i8::MAX` will be saturated to `i8::MAX`, and any value
|
||||
// less than `i8::MIN` will also be saturated to `i8::MIN`.
|
||||
let b = _mm512_set_epi16(
|
||||
200, 200, 200, 200, 200, 200, 200, 200, -200, -200, -200, -200, -200, -200, -200, -200,
|
||||
200, 200, 200, 200, 200, 200, 200, 200, -200, -200, -200, -200, -200, -200, -200, -200,
|
||||
);
|
||||
|
||||
// The pack* family of instructions in x86 operate in blocks
|
||||
// of 128-bit lanes, meaning the first 128-bit lane in `a` is converted and written
|
||||
// then the first 128-bit lane of `b`, followed by the second 128-bit lane in `a`, etc...
|
||||
// Because we are going from 16-bits to 8-bits our 128-bit block becomes 64-bits in
|
||||
// the output register.
|
||||
// This leaves us with 8x 8-bit values interleaved in the final register.
|
||||
#[rustfmt::skip]
|
||||
const DST: [i8; 64] = [
|
||||
120, 120, 120, 120, 120, 120, 120, 120,
|
||||
i8::MIN, i8::MIN, i8::MIN, i8::MIN, i8::MIN, i8::MIN, i8::MIN, i8::MIN,
|
||||
120, 120, 120, 120, 120, 120, 120, 120,
|
||||
i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX,
|
||||
120, 120, 120, 120, 120, 120, 120, 120,
|
||||
i8::MIN, i8::MIN, i8::MIN, i8::MIN, i8::MIN, i8::MIN, i8::MIN, i8::MIN,
|
||||
120, 120, 120, 120, 120, 120, 120, 120,
|
||||
i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX, i8::MAX,
|
||||
];
|
||||
let dst = _mm512_loadu_si512(DST.as_ptr().cast::<__m512i>());
|
||||
assert_eq_m512i(_mm512_packs_epi16(a, b), dst);
|
||||
}
|
||||
test_mm512_packs_epi16();
|
||||
|
||||
#[target_feature(enable = "avx512bw")]
|
||||
unsafe fn test_mm512_packus_epi16() {
|
||||
let a = _mm512_set1_epi16(120);
|
||||
|
||||
// Because `packus` instructions do unsigned saturation, we expect
|
||||
// that any value over `u8::MAX` will be saturated to `u8::MAX`, and any value
|
||||
// less than `u8::MIN` will also be saturated to `u8::MIN`.
|
||||
let b = _mm512_set_epi16(
|
||||
300, 300, 300, 300, 300, 300, 300, 300, -200, -200, -200, -200, -200, -200, -200, -200,
|
||||
300, 300, 300, 300, 300, 300, 300, 300, -200, -200, -200, -200, -200, -200, -200, -200,
|
||||
);
|
||||
|
||||
// See `test_mm512_packs_epi16` for an explanation of the output structure.
|
||||
#[rustfmt::skip]
|
||||
const DST: [u8; 64] = [
|
||||
120, 120, 120, 120, 120, 120, 120, 120,
|
||||
u8::MIN, u8::MIN, u8::MIN, u8::MIN, u8::MIN, u8::MIN, u8::MIN, u8::MIN,
|
||||
120, 120, 120, 120, 120, 120, 120, 120,
|
||||
u8::MAX, u8::MAX, u8::MAX, u8::MAX, u8::MAX, u8::MAX, u8::MAX, u8::MAX,
|
||||
120, 120, 120, 120, 120, 120, 120, 120,
|
||||
u8::MIN, u8::MIN, u8::MIN, u8::MIN, u8::MIN, u8::MIN, u8::MIN, u8::MIN,
|
||||
120, 120, 120, 120, 120, 120, 120, 120,
|
||||
u8::MAX, u8::MAX, u8::MAX, u8::MAX, u8::MAX, u8::MAX, u8::MAX, u8::MAX,
|
||||
];
|
||||
let dst = _mm512_loadu_si512(DST.as_ptr().cast::<__m512i>());
|
||||
assert_eq_m512i(_mm512_packus_epi16(a, b), dst);
|
||||
}
|
||||
test_mm512_packus_epi16();
|
||||
|
||||
#[target_feature(enable = "avx512bw")]
|
||||
unsafe fn test_mm512_packs_epi32() {
|
||||
let a = _mm512_set1_epi32(8_000);
|
||||
|
||||
// Because `packs` instructions do signed saturation, we expect
|
||||
// that any value over `i16::MAX` will be saturated to `i16::MAX`, and any value
|
||||
// less than `i16::MIN` will also be saturated to `i16::MIN`.
|
||||
let b = _mm512_set_epi32(
|
||||
50_000, 50_000, 50_000, 50_000, -50_000, -50_000, -50_000, -50_000, 50_000, 50_000,
|
||||
50_000, 50_000, -50_000, -50_000, -50_000, -50_000,
|
||||
);
|
||||
|
||||
// See `test_mm512_packs_epi16` for an explanation of the output structure.
|
||||
#[rustfmt::skip]
|
||||
const DST: [i16; 32] = [
|
||||
8_000, 8_000, 8_000, 8_000,
|
||||
i16::MIN, i16::MIN, i16::MIN, i16::MIN,
|
||||
8_000, 8_000, 8_000, 8_000,
|
||||
i16::MAX, i16::MAX, i16::MAX, i16::MAX,
|
||||
8_000, 8_000, 8_000, 8_000,
|
||||
i16::MIN, i16::MIN, i16::MIN, i16::MIN,
|
||||
8_000, 8_000, 8_000, 8_000,
|
||||
i16::MAX, i16::MAX, i16::MAX, i16::MAX,
|
||||
];
|
||||
let dst = _mm512_loadu_si512(DST.as_ptr().cast::<__m512i>());
|
||||
assert_eq_m512i(_mm512_packs_epi32(a, b), dst);
|
||||
}
|
||||
test_mm512_packs_epi32();
|
||||
|
||||
#[target_feature(enable = "avx512bw")]
|
||||
unsafe fn test_mm512_packus_epi32() {
|
||||
let a = _mm512_set1_epi32(8_000);
|
||||
|
||||
// Because `packus` instructions do unsigned saturation, we expect
|
||||
// that any value over `u16::MAX` will be saturated to `u16::MAX`, and any value
|
||||
// less than `u16::MIN` will also be saturated to `u16::MIN`.
|
||||
let b = _mm512_set_epi32(
|
||||
80_000, 80_000, 80_000, 80_000, -50_000, -50_000, -50_000, -50_000, 80_000, 80_000,
|
||||
80_000, 80_000, -50_000, -50_000, -50_000, -50_000,
|
||||
);
|
||||
|
||||
// See `test_mm512_packs_epi16` for an explanation of the output structure.
|
||||
#[rustfmt::skip]
|
||||
const DST: [u16; 32] = [
|
||||
8_000, 8_000, 8_000, 8_000,
|
||||
u16::MIN, u16::MIN, u16::MIN, u16::MIN,
|
||||
8_000, 8_000, 8_000, 8_000,
|
||||
u16::MAX, u16::MAX, u16::MAX, u16::MAX,
|
||||
8_000, 8_000, 8_000, 8_000,
|
||||
u16::MIN, u16::MIN, u16::MIN, u16::MIN,
|
||||
8_000, 8_000, 8_000, 8_000,
|
||||
u16::MAX, u16::MAX, u16::MAX, u16::MAX,
|
||||
];
|
||||
let dst = _mm512_loadu_si512(DST.as_ptr().cast::<__m512i>());
|
||||
assert_eq_m512i(_mm512_packus_epi32(a, b), dst);
|
||||
}
|
||||
test_mm512_packus_epi32();
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
unsafe fn assert_eq_m512i(a: __m512i, b: __m512i) {
|
||||
assert_eq!(transmute::<_, [i32; 16]>(a), transmute::<_, [i32; 16]>(b))
|
||||
assert_eq!(transmute::<_, [u16; 32]>(a), transmute::<_, [u16; 32]>(b))
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@ use std::ptr;
|
|||
|
||||
extern "system" {
|
||||
fn TlsAlloc() -> u32;
|
||||
fn TlsSetValue(key: u32, val: *mut c_void) -> bool;
|
||||
fn TlsSetValue(key: u32, val: *mut c_void) -> i32;
|
||||
fn TlsGetValue(key: u32) -> *mut c_void;
|
||||
fn TlsFree(key: u32) -> bool;
|
||||
fn TlsFree(key: u32) -> i32;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let key = unsafe { TlsAlloc() };
|
||||
assert!(unsafe { TlsSetValue(key, ptr::without_provenance_mut(1)) });
|
||||
assert!(unsafe { TlsSetValue(key, ptr::without_provenance_mut(1)) != 0 });
|
||||
assert_eq!(unsafe { TlsGetValue(key).addr() }, 1);
|
||||
assert!(unsafe { TlsFree(key) });
|
||||
assert!(unsafe { TlsFree(key) != 0 });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,21 +40,17 @@ pub unsafe fn read_all(
|
|||
return read_so_far as libc::ssize_t;
|
||||
}
|
||||
|
||||
/// Try to fill the given slice by reading from `fd`. Error if that many bytes could not be read.
|
||||
/// Try to fill the given slice by reading from `fd`. Panic if that many bytes could not be read.
|
||||
#[track_caller]
|
||||
pub fn read_all_into_slice(fd: libc::c_int, buf: &mut [u8]) -> Result<(), libc::ssize_t> {
|
||||
let res = unsafe { read_all(fd, buf.as_mut_ptr().cast(), buf.len()) };
|
||||
if res >= 0 {
|
||||
assert_eq!(res as usize, buf.len());
|
||||
Ok(())
|
||||
} else {
|
||||
Err(res)
|
||||
}
|
||||
pub fn read_all_into_slice(fd: libc::c_int, buf: &mut [u8]) -> io::Result<()> {
|
||||
let res = errno_result(unsafe { read_all(fd, buf.as_mut_ptr().cast(), buf.len()) })?;
|
||||
assert_eq!(res as usize, buf.len());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Read exactly `N` bytes from `fd`. Error if that many bytes could not be read.
|
||||
#[track_caller]
|
||||
pub fn read_all_into_array<const N: usize>(fd: libc::c_int) -> Result<[u8; N], libc::ssize_t> {
|
||||
pub fn read_all_into_array<const N: usize>(fd: libc::c_int) -> io::Result<[u8; N]> {
|
||||
let mut buf = [0; N];
|
||||
read_all_into_slice(fd, &mut buf)?;
|
||||
Ok(buf)
|
||||
|
|
@ -63,12 +59,20 @@ pub fn read_all_into_array<const N: usize>(fd: libc::c_int) -> Result<[u8; N], l
|
|||
/// Do a single read from `fd` and return the part of the buffer that was written into,
|
||||
/// and the rest.
|
||||
#[track_caller]
|
||||
pub fn read_into_slice(
|
||||
pub fn read_into_slice(fd: libc::c_int, buf: &mut [u8]) -> io::Result<(&mut [u8], &mut [u8])> {
|
||||
let res = errno_result(unsafe { libc::read(fd, buf.as_mut_ptr().cast(), buf.len()) })?;
|
||||
Ok(buf.split_at_mut(res as usize))
|
||||
}
|
||||
|
||||
/// Read from `fd` until we get EOF and return the part of the buffer that was written into,
|
||||
/// and the rest.
|
||||
#[track_caller]
|
||||
pub fn read_until_eof_into_slice(
|
||||
fd: libc::c_int,
|
||||
buf: &mut [u8],
|
||||
) -> Result<(&mut [u8], &mut [u8]), libc::ssize_t> {
|
||||
let res = unsafe { libc::read(fd, buf.as_mut_ptr().cast(), buf.len()) };
|
||||
if res >= 0 { Ok(buf.split_at_mut(res as usize)) } else { Err(res) }
|
||||
) -> io::Result<(&mut [u8], &mut [u8])> {
|
||||
let res = errno_result(unsafe { read_all(fd, buf.as_mut_ptr().cast(), buf.len()) })?;
|
||||
Ok(buf.split_at_mut(res as usize))
|
||||
}
|
||||
|
||||
pub unsafe fn write_all(
|
||||
|
|
@ -89,16 +93,12 @@ pub unsafe fn write_all(
|
|||
return written_so_far as libc::ssize_t;
|
||||
}
|
||||
|
||||
/// Write the entire `buf` to `fd`. Error if not all bytes could be written.
|
||||
/// Write the entire `buf` to `fd`. Panic if not all bytes could be written.
|
||||
#[track_caller]
|
||||
pub fn write_all_from_slice(fd: libc::c_int, buf: &[u8]) -> Result<(), libc::ssize_t> {
|
||||
let res = unsafe { write_all(fd, buf.as_ptr().cast(), buf.len()) };
|
||||
if res >= 0 {
|
||||
assert_eq!(res as usize, buf.len());
|
||||
Ok(())
|
||||
} else {
|
||||
Err(res)
|
||||
}
|
||||
pub fn write_all_from_slice(fd: libc::c_int, buf: &[u8]) -> io::Result<()> {
|
||||
let res = errno_result(unsafe { write_all(fd, buf.as_ptr().cast(), buf.len()) })?;
|
||||
assert_eq!(res as usize, buf.len());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android", target_os = "illumos"))]
|
||||
|
|
@ -113,7 +113,7 @@ pub mod epoll {
|
|||
|
||||
/// The libc epoll_event type doesn't fit to the EPOLLIN etc constants, so we have our
|
||||
/// own type. We also make the data field an int since we typically want to store FDs there.
|
||||
#[derive(PartialEq, Debug)]
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
pub struct Ev {
|
||||
pub events: c_int,
|
||||
pub data: c_int,
|
||||
|
|
@ -138,10 +138,10 @@ pub mod epoll {
|
|||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn check_epoll_wait_noblock<const N: usize>(epfd: i32, expected: &[Ev]) {
|
||||
pub fn check_epoll_wait<const N: usize>(epfd: i32, expected: &[Ev], timeout: i32) {
|
||||
let mut array: [libc::epoll_event; N] = [libc::epoll_event { events: 0, u64: 0 }; N];
|
||||
let num = errno_result(unsafe {
|
||||
libc::epoll_wait(epfd, array.as_mut_ptr(), N.try_into().unwrap(), 0)
|
||||
libc::epoll_wait(epfd, array.as_mut_ptr(), N.try_into().unwrap(), timeout)
|
||||
})
|
||||
.expect("epoll_wait returned an error");
|
||||
let got = &mut array[..num.try_into().unwrap()];
|
||||
|
|
@ -151,4 +151,9 @@ pub mod epoll {
|
|||
.collect::<Vec<_>>();
|
||||
assert_eq!(got, expected, "got wrong notifications");
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn check_epoll_wait_noblock<const N: usize>(epfd: i32, expected: &[Ev]) {
|
||||
check_epoll_wait::<N>(epfd, expected, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,6 +156,19 @@ extern "Rust" {
|
|||
/// Blocks the current execution if the argument is false
|
||||
pub fn miri_genmc_assume(condition: bool);
|
||||
|
||||
/// Miri-provided extern function to spawn a new thread in the interpreter.
|
||||
///
|
||||
/// Returns the thread id.
|
||||
///
|
||||
/// This is useful when no fundamental way of spawning threads is available, e.g. when using
|
||||
/// `no_std`.
|
||||
pub fn miri_thread_spawn(t: extern "Rust" fn(*mut ()), data: *mut ()) -> usize;
|
||||
|
||||
/// Miri-provided extern function to join a thread that was spawned by Miri.
|
||||
pub fn miri_thread_join(thread_id: usize) -> bool;
|
||||
|
||||
/// Indicate to Miri that this thread is busy-waiting in a spin loop.
|
||||
///
|
||||
/// As far as Miri is concerned, this is equivalent to `yield_now`.
|
||||
pub fn miri_spin_loop();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ error: crate-level attribute should be an inner attribute: add an exclamation ma
|
|||
LL | #[crate_name = "owo"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this function
|
||||
note: this attribute does not have an `!`, which means it is applied to this function
|
||||
--> $DIR/crate-only-as-outer.rs:5:1
|
||||
|
|
||||
LL | fn main() {}
|
||||
|
|
|
|||
|
|
@ -771,7 +771,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[crate_name]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this function
|
||||
note: this attribute does not have an `!`, which means it is applied to this function
|
||||
--> $DIR/malformed-attrs.rs:116:1
|
||||
|
|
||||
LL | / fn test() {
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ error: crate-level attribute should be an inner attribute: add an exclamation ma
|
|||
LL | #[no_std]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this extern crate
|
||||
note: this attribute does not have an `!`, which means it is applied to this extern crate
|
||||
--> $DIR/malformed-no-std.rs:26:1
|
||||
|
|
||||
LL | extern crate core;
|
||||
|
|
@ -75,7 +75,7 @@ error: crate-level attribute should be an inner attribute: add an exclamation ma
|
|||
LL | #[no_core]
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this extern crate
|
||||
note: this attribute does not have an `!`, which means it is applied to this extern crate
|
||||
--> $DIR/malformed-no-std.rs:26:1
|
||||
|
|
||||
LL | extern crate core;
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u
|
|||
LL | const S: &'static mut str = &mut " hello ";
|
||||
| ^^^^^^^^^^^^^^ this mutable borrow refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u
|
|||
LL | const B: *mut i32 = &mut 4;
|
||||
| ^^^^^^ this mutable borrow refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
|
||||
--> $DIR/mut_ref_in_final.rs:21:35
|
||||
|
|
@ -14,9 +14,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u
|
|||
LL | const B3: Option<&mut i32> = Some(&mut 42);
|
||||
| ^^^^^^^ this mutable borrow refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/mut_ref_in_final.rs:24:42
|
||||
|
|
@ -86,9 +86,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u
|
|||
LL | static RAW_MUT_CAST_S: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ };
|
||||
| ^^^^^^^ this mutable borrow refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
|
||||
--> $DIR/mut_ref_in_final.rs:73:54
|
||||
|
|
@ -96,9 +96,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u
|
|||
LL | static RAW_MUT_COERCE_S: SyncPtr<i32> = SyncPtr { x: &mut 0 };
|
||||
| ^^^^^^ this mutable borrow refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
|
||||
--> $DIR/mut_ref_in_final.rs:75:52
|
||||
|
|
@ -106,9 +106,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u
|
|||
LL | const RAW_MUT_CAST_C: SyncPtr<i32> = SyncPtr { x : &mut 42 as *mut _ as *const _ };
|
||||
| ^^^^^^^ this mutable borrow refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error[E0764]: mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
|
||||
--> $DIR/mut_ref_in_final.rs:77:53
|
||||
|
|
@ -116,9 +116,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u
|
|||
LL | const RAW_MUT_COERCE_C: SyncPtr<i32> = SyncPtr { x: &mut 0 };
|
||||
| ^^^^^^ this mutable borrow refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error[E0080]: constructing invalid value at .<enum-variant(Some)>.0: encountered a dangling reference (0x2a[noalloc] has no provenance)
|
||||
--> $DIR/mut_ref_in_final.rs:86:5
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif
|
|||
LL | const BAZ: &Foo = &FOO;
|
||||
| ^^^^ this borrow of an interior mutable value refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error[E0716]: temporary value dropped while borrowed
|
||||
--> $DIR/const-promoted-opaque.rs:40:26
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u
|
|||
LL | const C1: &'static mut [usize] = &mut [];
|
||||
| ^^^^^^^ this mutable borrow refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif
|
|||
LL | const B: &'static UnsafeCell<usize> = &A;
|
||||
| ^^ this borrow of an interior mutable value refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
|
||||
--> $DIR/issue-17718-const-borrow.rs:9:39
|
||||
|
|
@ -14,9 +14,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif
|
|||
LL | const E: &'static UnsafeCell<usize> = &D.a;
|
||||
| ^^^^ this borrow of an interior mutable value refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
|
||||
--> $DIR/issue-17718-const-borrow.rs:11:23
|
||||
|
|
@ -24,9 +24,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif
|
|||
LL | const F: &'static C = &D;
|
||||
| ^^ this borrow of an interior mutable value refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif
|
|||
LL | &{a}
|
||||
| ^^^^ this borrow of an interior mutable value refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif
|
|||
LL | &{a}
|
||||
| ^^^^ this borrow of an interior mutable value refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif
|
|||
LL | &{a.0}
|
||||
| ^^^^^^ this borrow of an interior mutable value refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif
|
|||
LL | static RAW_SYNC_S: SyncPtr<Cell<i32>> = SyncPtr { x: &Cell::new(42) };
|
||||
| ^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
|
||||
--> $DIR/refs-to-cell-in-final.rs:15:53
|
||||
|
|
@ -14,9 +14,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif
|
|||
LL | const RAW_SYNC_C: SyncPtr<Cell<i32>> = SyncPtr { x: &Cell::new(42) };
|
||||
| ^^^^^^^^^^^^^^ this borrow of an interior mutable value refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
|
||||
--> $DIR/refs-to-cell-in-final.rs:41:57
|
||||
|
|
@ -31,9 +31,9 @@ LL | | x
|
|||
LL | | };
|
||||
| |_^ this borrow of an interior mutable value refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u
|
|||
LL | static OH_NO: &mut i32 = &mut 42;
|
||||
| ^^^^^^^ this mutable borrow refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error[E0594]: cannot assign to `*OH_NO`, as `OH_NO` is an immutable static item
|
||||
--> $DIR/write_to_static_via_mut_ref.rs:4:5
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u
|
|||
LL | const CR: &'static mut i32 = &mut C;
|
||||
| ^^^^^^ this mutable borrow refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error[E0596]: cannot borrow immutable static item `X` as mutable
|
||||
--> $DIR/E0017.rs:11:39
|
||||
|
|
@ -52,9 +52,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u
|
|||
LL | static CONST_REF: &'static mut i32 = &mut C;
|
||||
| ^^^^^^ this mutable borrow refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error: aborting due to 3 previous errors; 2 warnings emitted
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif
|
|||
LL | const B: &'static AtomicUsize = &A;
|
||||
| ^^ this borrow of an interior mutable value refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error[E0492]: interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
|
||||
--> $DIR/E0492.rs:5:34
|
||||
|
|
@ -14,9 +14,9 @@ error[E0492]: interior mutable shared borrows of temporaries that have their lif
|
|||
LL | static C: &'static AtomicUsize = &A;
|
||||
| ^^ this borrow of an interior mutable value refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -525,25 +525,25 @@ mod macro_escape {
|
|||
#[no_std]
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
mod no_std {
|
||||
//~^ NOTE This attribute does not have an `!`, which means it is applied to this module
|
||||
//~^ NOTE this attribute does not have an `!`, which means it is applied to this module
|
||||
mod inner { #![no_std] }
|
||||
//~^ WARN the `#![no_std]` attribute can only be used at the crate root
|
||||
|
||||
#[no_std] fn f() { }
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this function
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this function
|
||||
|
||||
#[no_std] struct S;
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this struct
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this struct
|
||||
|
||||
#[no_std] type T = S;
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this type alias
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this type alias
|
||||
|
||||
#[no_std] impl S { }
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this implementation block
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this implementation block
|
||||
}
|
||||
|
||||
// At time of authorship, #[proc_macro_derive = "2500"] signals error
|
||||
|
|
@ -786,25 +786,25 @@ mod must_use {
|
|||
#[windows_subsystem = "windows"]
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
mod windows_subsystem {
|
||||
//~^ NOTE This attribute does not have an `!`, which means it is applied to this module
|
||||
//~^ NOTE this attribute does not have an `!`, which means it is applied to this module
|
||||
mod inner { #![windows_subsystem="windows"] }
|
||||
//~^ WARN the `#![windows_subsystem]` attribute can only be used at the crate root
|
||||
|
||||
#[windows_subsystem = "windows"] fn f() { }
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this function
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this function
|
||||
|
||||
#[windows_subsystem = "windows"] struct S;
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this struct
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this struct
|
||||
|
||||
#[windows_subsystem = "windows"] type T = S;
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this type alias
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this type alias
|
||||
|
||||
#[windows_subsystem = "windows"] impl S { }
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this implementation block
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this implementation block
|
||||
}
|
||||
|
||||
// BROKEN USES OF CRATE-LEVEL BUILT-IN ATTRIBUTES
|
||||
|
|
@ -812,25 +812,25 @@ mod windows_subsystem {
|
|||
#[crate_name = "0900"]
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
mod crate_name {
|
||||
//~^ NOTE This attribute does not have an `!`, which means it is applied to this module
|
||||
//~^ NOTE this attribute does not have an `!`, which means it is applied to this module
|
||||
mod inner { #![crate_name="0900"] }
|
||||
//~^ WARN the `#![crate_name]` attribute can only be used at the crate root
|
||||
|
||||
#[crate_name = "0900"] fn f() { }
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this function
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this function
|
||||
|
||||
#[crate_name = "0900"] struct S;
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this struct
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this struct
|
||||
|
||||
#[crate_name = "0900"] type T = S;
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this type alias
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this type alias
|
||||
|
||||
#[crate_name = "0900"] impl S { }
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this implementation block
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this implementation block
|
||||
}
|
||||
|
||||
#[crate_type = "0800"]
|
||||
|
|
@ -885,25 +885,25 @@ mod feature {
|
|||
#[no_main]
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
mod no_main_1 {
|
||||
//~^ NOTE: This attribute does not have an `!`, which means it is applied to this module
|
||||
//~^ NOTE: this attribute does not have an `!`, which means it is applied to this module
|
||||
mod inner { #![no_main] }
|
||||
//~^ WARN the `#![no_main]` attribute can only be used at the crate root
|
||||
|
||||
#[no_main] fn f() { }
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this function
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this function
|
||||
|
||||
#[no_main] struct S;
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this struct
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this struct
|
||||
|
||||
#[no_main] type T = S;
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this type alias
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this type alias
|
||||
|
||||
#[no_main] impl S { }
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this implementation
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this implementation
|
||||
}
|
||||
|
||||
#[no_builtins]
|
||||
|
|
@ -933,49 +933,49 @@ mod no_builtins {
|
|||
#[recursion_limit="0200"]
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
mod recursion_limit {
|
||||
//~^ NOTE This attribute does not have an `!`, which means it is applied to this module
|
||||
//~^ NOTE this attribute does not have an `!`, which means it is applied to this module
|
||||
mod inner { #![recursion_limit="0200"] }
|
||||
//~^ WARN the `#![recursion_limit]` attribute can only be used at the crate root
|
||||
|
||||
#[recursion_limit="0200"] fn f() { }
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this function
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this function
|
||||
|
||||
#[recursion_limit="0200"] struct S;
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this struct
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this struct
|
||||
|
||||
#[recursion_limit="0200"] type T = S;
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this type alias
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this type alias
|
||||
|
||||
#[recursion_limit="0200"] impl S { }
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this implementation block
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this implementation block
|
||||
}
|
||||
|
||||
#[type_length_limit="0100"]
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
mod type_length_limit {
|
||||
//~^ NOTE This attribute does not have an `!`, which means it is applied to this module
|
||||
//~^ NOTE this attribute does not have an `!`, which means it is applied to this module
|
||||
mod inner { #![type_length_limit="0100"] }
|
||||
//~^ WARN the `#![type_length_limit]` attribute can only be used at the crate root
|
||||
|
||||
#[type_length_limit="0100"] fn f() { }
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this function
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this function
|
||||
|
||||
#[type_length_limit="0100"] struct S;
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this struct
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this struct
|
||||
|
||||
#[type_length_limit="0100"] type T = S;
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this type alias
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this type alias
|
||||
|
||||
#[type_length_limit="0100"] impl S { }
|
||||
//~^ WARN crate-level attribute should be an inner attribute
|
||||
//~| NOTE This attribute does not have an `!`, which means it is applied to this implementation block
|
||||
//~| NOTE this attribute does not have an `!`, which means it is applied to this implementation block
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -935,7 +935,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[no_std]
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this module
|
||||
note: this attribute does not have an `!`, which means it is applied to this module
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:527:1
|
||||
|
|
||||
LL | / mod no_std {
|
||||
|
|
@ -957,7 +957,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[no_std] fn f() { }
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this function
|
||||
note: this attribute does not have an `!`, which means it is applied to this function
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:532:15
|
||||
|
|
||||
LL | #[no_std] fn f() { }
|
||||
|
|
@ -969,7 +969,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[no_std] struct S;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this struct
|
||||
note: this attribute does not have an `!`, which means it is applied to this struct
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:536:15
|
||||
|
|
||||
LL | #[no_std] struct S;
|
||||
|
|
@ -981,7 +981,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[no_std] type T = S;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this type alias
|
||||
note: this attribute does not have an `!`, which means it is applied to this type alias
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:540:15
|
||||
|
|
||||
LL | #[no_std] type T = S;
|
||||
|
|
@ -993,7 +993,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[no_std] impl S { }
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this implementation block
|
||||
note: this attribute does not have an `!`, which means it is applied to this implementation block
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:15
|
||||
|
|
||||
LL | #[no_std] impl S { }
|
||||
|
|
@ -1212,7 +1212,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[windows_subsystem = "windows"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this module
|
||||
note: this attribute does not have an `!`, which means it is applied to this module
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:788:1
|
||||
|
|
||||
LL | / mod windows_subsystem {
|
||||
|
|
@ -1234,7 +1234,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[windows_subsystem = "windows"] fn f() { }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this function
|
||||
note: this attribute does not have an `!`, which means it is applied to this function
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:38
|
||||
|
|
||||
LL | #[windows_subsystem = "windows"] fn f() { }
|
||||
|
|
@ -1246,7 +1246,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[windows_subsystem = "windows"] struct S;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this struct
|
||||
note: this attribute does not have an `!`, which means it is applied to this struct
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:797:38
|
||||
|
|
||||
LL | #[windows_subsystem = "windows"] struct S;
|
||||
|
|
@ -1258,7 +1258,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[windows_subsystem = "windows"] type T = S;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this type alias
|
||||
note: this attribute does not have an `!`, which means it is applied to this type alias
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:801:38
|
||||
|
|
||||
LL | #[windows_subsystem = "windows"] type T = S;
|
||||
|
|
@ -1270,7 +1270,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[windows_subsystem = "windows"] impl S { }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this implementation block
|
||||
note: this attribute does not have an `!`, which means it is applied to this implementation block
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:805:38
|
||||
|
|
||||
LL | #[windows_subsystem = "windows"] impl S { }
|
||||
|
|
@ -1282,7 +1282,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[crate_name = "0900"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this module
|
||||
note: this attribute does not have an `!`, which means it is applied to this module
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:1
|
||||
|
|
||||
LL | / mod crate_name {
|
||||
|
|
@ -1304,7 +1304,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[crate_name = "0900"] fn f() { }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this function
|
||||
note: this attribute does not have an `!`, which means it is applied to this function
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:819:28
|
||||
|
|
||||
LL | #[crate_name = "0900"] fn f() { }
|
||||
|
|
@ -1316,7 +1316,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[crate_name = "0900"] struct S;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this struct
|
||||
note: this attribute does not have an `!`, which means it is applied to this struct
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:823:28
|
||||
|
|
||||
LL | #[crate_name = "0900"] struct S;
|
||||
|
|
@ -1328,7 +1328,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[crate_name = "0900"] type T = S;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this type alias
|
||||
note: this attribute does not have an `!`, which means it is applied to this type alias
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:827:28
|
||||
|
|
||||
LL | #[crate_name = "0900"] type T = S;
|
||||
|
|
@ -1340,7 +1340,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[crate_name = "0900"] impl S { }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this implementation block
|
||||
note: this attribute does not have an `!`, which means it is applied to this implementation block
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:831:28
|
||||
|
|
||||
LL | #[crate_name = "0900"] impl S { }
|
||||
|
|
@ -1352,7 +1352,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[no_main]
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this module
|
||||
note: this attribute does not have an `!`, which means it is applied to this module
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:887:1
|
||||
|
|
||||
LL | / mod no_main_1 {
|
||||
|
|
@ -1374,7 +1374,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[no_main] fn f() { }
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this function
|
||||
note: this attribute does not have an `!`, which means it is applied to this function
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:892:16
|
||||
|
|
||||
LL | #[no_main] fn f() { }
|
||||
|
|
@ -1386,7 +1386,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[no_main] struct S;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this struct
|
||||
note: this attribute does not have an `!`, which means it is applied to this struct
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:896:16
|
||||
|
|
||||
LL | #[no_main] struct S;
|
||||
|
|
@ -1398,7 +1398,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[no_main] type T = S;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this type alias
|
||||
note: this attribute does not have an `!`, which means it is applied to this type alias
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:900:16
|
||||
|
|
||||
LL | #[no_main] type T = S;
|
||||
|
|
@ -1410,7 +1410,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[no_main] impl S { }
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this implementation block
|
||||
note: this attribute does not have an `!`, which means it is applied to this implementation block
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:904:16
|
||||
|
|
||||
LL | #[no_main] impl S { }
|
||||
|
|
@ -1422,7 +1422,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[recursion_limit="0200"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this module
|
||||
note: this attribute does not have an `!`, which means it is applied to this module
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:935:1
|
||||
|
|
||||
LL | / mod recursion_limit {
|
||||
|
|
@ -1444,7 +1444,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[recursion_limit="0200"] fn f() { }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this function
|
||||
note: this attribute does not have an `!`, which means it is applied to this function
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:940:31
|
||||
|
|
||||
LL | #[recursion_limit="0200"] fn f() { }
|
||||
|
|
@ -1456,7 +1456,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[recursion_limit="0200"] struct S;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this struct
|
||||
note: this attribute does not have an `!`, which means it is applied to this struct
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:944:31
|
||||
|
|
||||
LL | #[recursion_limit="0200"] struct S;
|
||||
|
|
@ -1468,7 +1468,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[recursion_limit="0200"] type T = S;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this type alias
|
||||
note: this attribute does not have an `!`, which means it is applied to this type alias
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:948:31
|
||||
|
|
||||
LL | #[recursion_limit="0200"] type T = S;
|
||||
|
|
@ -1480,7 +1480,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[recursion_limit="0200"] impl S { }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this implementation block
|
||||
note: this attribute does not have an `!`, which means it is applied to this implementation block
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:952:31
|
||||
|
|
||||
LL | #[recursion_limit="0200"] impl S { }
|
||||
|
|
@ -1492,7 +1492,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[type_length_limit="0100"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this module
|
||||
note: this attribute does not have an `!`, which means it is applied to this module
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:959:1
|
||||
|
|
||||
LL | / mod type_length_limit {
|
||||
|
|
@ -1514,7 +1514,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[type_length_limit="0100"] fn f() { }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this function
|
||||
note: this attribute does not have an `!`, which means it is applied to this function
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:964:33
|
||||
|
|
||||
LL | #[type_length_limit="0100"] fn f() { }
|
||||
|
|
@ -1526,7 +1526,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[type_length_limit="0100"] struct S;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this struct
|
||||
note: this attribute does not have an `!`, which means it is applied to this struct
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:968:33
|
||||
|
|
||||
LL | #[type_length_limit="0100"] struct S;
|
||||
|
|
@ -1538,7 +1538,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[type_length_limit="0100"] type T = S;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this type alias
|
||||
note: this attribute does not have an `!`, which means it is applied to this type alias
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:972:33
|
||||
|
|
||||
LL | #[type_length_limit="0100"] type T = S;
|
||||
|
|
@ -1550,7 +1550,7 @@ warning: crate-level attribute should be an inner attribute: add an exclamation
|
|||
LL | #[type_length_limit="0100"] impl S { }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this implementation block
|
||||
note: this attribute does not have an `!`, which means it is applied to this implementation block
|
||||
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:976:33
|
||||
|
|
||||
LL | #[type_length_limit="0100"] impl S { }
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u
|
|||
LL | static buf: &mut [u8] = &mut [1u8,2,3,4,5,7];
|
||||
| ^^^^^^^^^^^^^^^^^^^^ this mutable borrow refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error[E0594]: cannot assign to `buf[_]`, as `buf` is an immutable static item
|
||||
--> $DIR/issue-46604.rs:6:5
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ error: moving 9999 bytes
|
|||
LL | let _ = NotBox::new(data);
|
||||
| ^^^^ value moved from here
|
||||
|
|
||||
= note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
= note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
note: the lint level is defined here
|
||||
--> $DIR/copy_into_box_rc_arc.rs:1:9
|
||||
|
|
||||
|
|
@ -19,7 +19,7 @@ LL | | data,
|
|||
LL | | }
|
||||
| |_________^ value moved from here
|
||||
|
|
||||
= note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
= note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ error: moving 9999 bytes
|
|||
LL | one_arg(Data([0; 9999]));
|
||||
| ^^^^^^^^^^^^^^^ value moved from here
|
||||
|
|
||||
= note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
= note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
note: the lint level is defined here
|
||||
--> $DIR/copy_into_fn.rs:5:9
|
||||
|
|
||||
|
|
@ -17,7 +17,7 @@ error: moving 9999 bytes
|
|||
LL | many_args(Data([0; 9999]), true, Data([0; 9999]));
|
||||
| ^^^^^^^^^^^^^^^ value moved from here
|
||||
|
|
||||
= note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
= note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
|
||||
error: moving 9999 bytes
|
||||
--> $DIR/copy_into_fn.rs:17:38
|
||||
|
|
@ -25,7 +25,7 @@ error: moving 9999 bytes
|
|||
LL | many_args(Data([0; 9999]), true, Data([0; 9999]));
|
||||
| ^^^^^^^^^^^^^^^ value moved from here
|
||||
|
|
||||
= note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
= note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ error: moving 9999 bytes
|
|||
LL | let cell = std::cell::UnsafeCell::new(data);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ value moved from here
|
||||
|
|
||||
= note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
= note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
note: the lint level is defined here
|
||||
--> $DIR/inline_mir.rs:2:9
|
||||
|
|
||||
|
|
@ -17,7 +17,7 @@ error: moving 9999 bytes
|
|||
LL | std::hint::black_box(cell);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ value moved from here
|
||||
|
|
||||
= note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
= note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ error: moving 10024 bytes
|
|||
LL | let z = (x, 42);
|
||||
| ^ value moved from here
|
||||
|
|
||||
= note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
= note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
note: the lint level is defined here
|
||||
--> $DIR/large_future.rs:1:9
|
||||
|
|
||||
|
|
@ -17,7 +17,7 @@ error: moving 10024 bytes
|
|||
LL | let a = z.0;
|
||||
| ^^^ value moved from here
|
||||
|
|
||||
= note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
= note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ error: moving 10024 bytes
|
|||
LL | let z = (x, 42);
|
||||
| ^ value moved from here
|
||||
|
|
||||
= note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
= note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
note: the lint level is defined here
|
||||
--> $DIR/large_future.rs:1:9
|
||||
|
|
||||
|
|
@ -17,7 +17,7 @@ error: moving 10024 bytes
|
|||
LL | let a = z.0;
|
||||
| ^^^ value moved from here
|
||||
|
|
||||
= note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
= note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ error: moving 9999 bytes
|
|||
LL | data,
|
||||
| ^^^^ value moved from here
|
||||
|
|
||||
= note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
= note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
note: the lint level is defined here
|
||||
--> $DIR/move_into_box_rc_arc.rs:1:9
|
||||
|
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ error: moving 9999 bytes
|
|||
LL | let data = Data([100; 9999]);
|
||||
| ^^^^^^^^^^^^^^^^^ value moved from here
|
||||
|
|
||||
= note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
= note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
note: the lint level is defined here
|
||||
--> $DIR/move_into_fn.rs:5:9
|
||||
|
|
||||
|
|
@ -17,7 +17,7 @@ error: moving 9999 bytes
|
|||
LL | take_data(data);
|
||||
| ^^^^ value moved from here
|
||||
|
|
||||
= note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
= note: the current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ error: crate-level attribute should be an inner attribute: add an exclamation ma
|
|||
LL | #[crate_name = concat !()]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this macro def
|
||||
note: this attribute does not have an `!`, which means it is applied to this macro def
|
||||
--> $DIR/concat-in-crate-name-issue-137687.rs:5:1
|
||||
|
|
||||
LL | / macro_rules! a {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ error: crate-level attribute should be an inner attribute: add an exclamation ma
|
|||
LL | #[recursion_limit="1"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: This attribute does not have an `!`, which means it is applied to this macro def
|
||||
note: this attribute does not have an `!`, which means it is applied to this macro def
|
||||
--> $DIR/unused-attr-macro-rules.rs:12:1
|
||||
|
|
||||
LL | / macro_rules! foo {
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ error[E0764]: mutable borrows of temporaries that have their lifetime extended u
|
|||
LL | static TEST: &'static mut [isize] = &mut [];
|
||||
| ^^^^^^^ this mutable borrow refers to such a temporary
|
||||
|
|
||||
= note: Temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: To avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
= note: temporaries in constants and statics can have their lifetime extended until the end of the program
|
||||
= note: to avoid accidentally creating global mutable state, such temporaries must be immutable
|
||||
= help: if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ error: item annotated with `#[unstable_feature_bound]` should not be stable
|
|||
LL | fn bar() {}
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= help: If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]`
|
||||
= help: if this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -1465,6 +1465,7 @@ compiler = [
|
|||
"@oli-obk",
|
||||
"@petrochenkov",
|
||||
"@SparrowLii",
|
||||
"@tiif",
|
||||
"@WaffleLapkin",
|
||||
"@wesleywiser",
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue