Auto merge of #139845 - Zalathar:rollup-u5u5y1v, r=Zalathar
Rollup of 17 pull requests Successful merges: - #138374 (Enable contracts for const functions) - #138380 (ci: add runners for vanilla LLVM 20) - #138393 (Allow const patterns of matches to contain pattern types) - #139517 (std: sys: process: uefi: Use NULL stdin by default) - #139554 (std: add Output::exit_ok) - #139660 (compiletest: Add an experimental new executor to replace libtest) - #139669 (Overhaul `AssocItem`) - #139671 (Proc macro span API redesign: Replace proc_macro::SourceFile by Span::{file, local_file}) - #139750 (std/thread: Use default stack size from menuconfig for NuttX) - #139772 (Remove `hir::Map`) - #139785 (Let CStrings be either 1 or 2 byte aligned.) - #139789 (do not unnecessarily leak auto traits in item bounds) - #139791 (drop global where-bounds before merging candidates) - #139798 (normalize: prefer `ParamEnv` over `AliasBound` candidates) - #139822 (Fix: Map EOPNOTSUPP to ErrorKind::Unsupported on Unix) - #139833 (Fix some HIR pretty-printing problems) - #139836 (Basic tests of MPMC receiver cloning) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
f433fa46b0
173 changed files with 2499 additions and 994 deletions
|
@ -2,19 +2,23 @@
|
|||
|
||||
pub use crate::macros::builtin::{contracts_ensures as ensures, contracts_requires as requires};
|
||||
|
||||
/// Emitted by rustc as a desugaring of `#[ensures(PRED)] fn foo() -> R { ... [return R;] ... }`
|
||||
/// into: `fn foo() { let _check = build_check_ensures(|ret| PRED) ... [return _check(R);] ... }`
|
||||
/// (including the implicit return of the tail expression, if any).
|
||||
/// This is an identity function used as part of the desugaring of the `#[ensures]` attribute.
|
||||
///
|
||||
/// This is an existing hack to allow users to omit the type of the return value in their ensures
|
||||
/// attribute.
|
||||
///
|
||||
/// Ideally, rustc should be able to generate the type annotation.
|
||||
/// The existing lowering logic makes it rather hard to add the explicit type annotation,
|
||||
/// while the function call is fairly straight forward.
|
||||
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
|
||||
// Similar to `contract_check_requires`, we need to use the user-facing
|
||||
// `contracts` feature rather than the perma-unstable `contracts_internals`.
|
||||
// Const-checking doesn't honor allow_internal_unstable logic used by contract expansion.
|
||||
#[rustc_const_unstable(feature = "contracts", issue = "128044")]
|
||||
#[lang = "contract_build_check_ensures"]
|
||||
#[track_caller]
|
||||
pub fn build_check_ensures<Ret, C>(cond: C) -> impl (Fn(Ret) -> Ret) + Copy
|
||||
pub const fn build_check_ensures<Ret, C>(cond: C) -> C
|
||||
where
|
||||
C: for<'a> Fn(&'a Ret) -> bool + Copy + 'static,
|
||||
C: Fn(&Ret) -> bool + Copy + 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
move |ret| {
|
||||
crate::intrinsics::contract_check_ensures(&ret, cond);
|
||||
ret
|
||||
}
|
||||
cond
|
||||
}
|
||||
|
|
|
@ -3402,20 +3402,62 @@ pub const fn contract_checks() -> bool {
|
|||
///
|
||||
/// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition
|
||||
/// returns false.
|
||||
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
|
||||
///
|
||||
/// Note that this function is a no-op during constant evaluation.
|
||||
#[unstable(feature = "contracts_internals", issue = "128044")]
|
||||
// Calls to this function get inserted by an AST expansion pass, which uses the equivalent of
|
||||
// `#[allow_internal_unstable]` to allow using `contracts_internals` functions. Const-checking
|
||||
// doesn't honor `#[allow_internal_unstable]`, so for the const feature gate we use the user-facing
|
||||
// `contracts` feature rather than the perma-unstable `contracts_internals`
|
||||
#[rustc_const_unstable(feature = "contracts", issue = "128044")]
|
||||
#[lang = "contract_check_requires"]
|
||||
#[rustc_intrinsic]
|
||||
pub fn contract_check_requires<C: Fn() -> bool>(cond: C) {
|
||||
if contract_checks() && !cond() {
|
||||
// Emit no unwind panic in case this was a safety requirement.
|
||||
crate::panicking::panic_nounwind("failed requires check");
|
||||
}
|
||||
pub const fn contract_check_requires<C: Fn() -> bool + Copy>(cond: C) {
|
||||
const_eval_select!(
|
||||
@capture[C: Fn() -> bool + Copy] { cond: C } :
|
||||
if const {
|
||||
// Do nothing
|
||||
} else {
|
||||
if contract_checks() && !cond() {
|
||||
// Emit no unwind panic in case this was a safety requirement.
|
||||
crate::panicking::panic_nounwind("failed requires check");
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// Check if the post-condition `cond` has been met.
|
||||
///
|
||||
/// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition
|
||||
/// returns false.
|
||||
///
|
||||
/// Note that this function is a no-op during constant evaluation.
|
||||
#[cfg(not(bootstrap))]
|
||||
#[unstable(feature = "contracts_internals", issue = "128044")]
|
||||
// Similar to `contract_check_requires`, we need to use the user-facing
|
||||
// `contracts` feature rather than the perma-unstable `contracts_internals`.
|
||||
// Const-checking doesn't honor allow_internal_unstable logic used by contract expansion.
|
||||
#[rustc_const_unstable(feature = "contracts", issue = "128044")]
|
||||
#[lang = "contract_check_ensures"]
|
||||
#[rustc_intrinsic]
|
||||
pub const fn contract_check_ensures<C: Fn(&Ret) -> bool + Copy, Ret>(cond: C, ret: Ret) -> Ret {
|
||||
const_eval_select!(
|
||||
@capture[C: Fn(&Ret) -> bool + Copy, Ret] { cond: C, ret: Ret } -> Ret :
|
||||
if const {
|
||||
// Do nothing
|
||||
ret
|
||||
} else {
|
||||
if contract_checks() && !cond(&ret) {
|
||||
// Emit no unwind panic in case this was a safety requirement.
|
||||
crate::panicking::panic_nounwind("failed ensures check");
|
||||
}
|
||||
ret
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// This is the old version of contract_check_ensures kept here for bootstrap only.
|
||||
#[cfg(bootstrap)]
|
||||
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
|
||||
#[rustc_intrinsic]
|
||||
pub fn contract_check_ensures<'a, Ret, C: Fn(&'a Ret) -> bool>(ret: &'a Ret, cond: C) {
|
||||
|
|
|
@ -101,7 +101,6 @@
|
|||
#![feature(bstr)]
|
||||
#![feature(bstr_internals)]
|
||||
#![feature(cfg_match)]
|
||||
#![feature(closure_track_caller)]
|
||||
#![feature(const_carrying_mul_add)]
|
||||
#![feature(const_eval_select)]
|
||||
#![feature(core_intrinsics)]
|
||||
|
|
|
@ -111,12 +111,6 @@ impl Clone for TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
impl Clone for SourceFile {
|
||||
fn clone(&self) -> Self {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Span {
|
||||
pub(crate) fn def_site() -> Span {
|
||||
Bridge::with(|bridge| bridge.globals.def_site)
|
||||
|
|
|
@ -81,16 +81,8 @@ macro_rules! with_api {
|
|||
$self: $S::TokenStream
|
||||
) -> Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>;
|
||||
},
|
||||
SourceFile {
|
||||
fn drop($self: $S::SourceFile);
|
||||
fn clone($self: &$S::SourceFile) -> $S::SourceFile;
|
||||
fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool;
|
||||
fn path($self: &$S::SourceFile) -> String;
|
||||
fn is_real($self: &$S::SourceFile) -> bool;
|
||||
},
|
||||
Span {
|
||||
fn debug($self: $S::Span) -> String;
|
||||
fn source_file($self: $S::Span) -> $S::SourceFile;
|
||||
fn parent($self: $S::Span) -> Option<$S::Span>;
|
||||
fn source($self: $S::Span) -> $S::Span;
|
||||
fn byte_range($self: $S::Span) -> Range<usize>;
|
||||
|
@ -98,6 +90,8 @@ macro_rules! with_api {
|
|||
fn end($self: $S::Span) -> $S::Span;
|
||||
fn line($self: $S::Span) -> usize;
|
||||
fn column($self: $S::Span) -> usize;
|
||||
fn file($self: $S::Span) -> String;
|
||||
fn local_file($self: $S::Span) -> Option<String>;
|
||||
fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>;
|
||||
fn subspan($self: $S::Span, start: Bound<usize>, end: Bound<usize>) -> Option<$S::Span>;
|
||||
fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span;
|
||||
|
@ -120,7 +114,6 @@ macro_rules! with_api_handle_types {
|
|||
'owned:
|
||||
FreeFunctions,
|
||||
TokenStream,
|
||||
SourceFile,
|
||||
|
||||
'interned:
|
||||
Span,
|
||||
|
|
|
@ -82,7 +82,6 @@ with_api_handle_types!(define_server_handles);
|
|||
pub trait Types {
|
||||
type FreeFunctions: 'static;
|
||||
type TokenStream: 'static + Clone;
|
||||
type SourceFile: 'static + Clone;
|
||||
type Span: 'static + Copy + Eq + Hash;
|
||||
type Symbol: 'static;
|
||||
}
|
||||
|
|
|
@ -491,12 +491,6 @@ impl Span {
|
|||
Span(bridge::client::Span::mixed_site())
|
||||
}
|
||||
|
||||
/// The original source file into which this span points.
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
pub fn source_file(&self) -> SourceFile {
|
||||
SourceFile(self.0.source_file())
|
||||
}
|
||||
|
||||
/// The `Span` for the tokens in the previous macro expansion from which
|
||||
/// `self` was generated from, if any.
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
|
@ -546,6 +540,25 @@ impl Span {
|
|||
self.0.column()
|
||||
}
|
||||
|
||||
/// The path to the source file in which this span occurs, for display purposes.
|
||||
///
|
||||
/// This might not correspond to a valid file system path.
|
||||
/// It might be remapped, or might be an artificial path such as `"<macro expansion>"`.
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
pub fn file(&self) -> String {
|
||||
self.0.file()
|
||||
}
|
||||
|
||||
/// The path to the source file in which this span occurs on disk.
|
||||
///
|
||||
/// This is the actual path on disk. It is unaffected by path remapping.
|
||||
///
|
||||
/// This path should not be embedded in the output of the macro; prefer `file()` instead.
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
pub fn local_file(&self) -> Option<PathBuf> {
|
||||
self.0.local_file().map(|s| PathBuf::from(s))
|
||||
}
|
||||
|
||||
/// Creates a new span encompassing `self` and `other`.
|
||||
///
|
||||
/// Returns `None` if `self` and `other` are from different files.
|
||||
|
@ -614,58 +627,6 @@ impl fmt::Debug for Span {
|
|||
}
|
||||
}
|
||||
|
||||
/// The source file of a given `Span`.
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
#[derive(Clone)]
|
||||
pub struct SourceFile(bridge::client::SourceFile);
|
||||
|
||||
impl SourceFile {
|
||||
/// Gets the path to this source file.
|
||||
///
|
||||
/// ### Note
|
||||
/// If the code span associated with this `SourceFile` was generated by an external macro, this
|
||||
/// macro, this might not be an actual path on the filesystem. Use [`is_real`] to check.
|
||||
///
|
||||
/// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on
|
||||
/// the command line, the path as given might not actually be valid.
|
||||
///
|
||||
/// [`is_real`]: Self::is_real
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
pub fn path(&self) -> PathBuf {
|
||||
PathBuf::from(self.0.path())
|
||||
}
|
||||
|
||||
/// Returns `true` if this source file is a real source file, and not generated by an external
|
||||
/// macro's expansion.
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
pub fn is_real(&self) -> bool {
|
||||
// This is a hack until intercrate spans are implemented and we can have real source files
|
||||
// for spans generated in external macros.
|
||||
// https://github.com/rust-lang/rust/pull/43604#issuecomment-333334368
|
||||
self.0.is_real()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
impl fmt::Debug for SourceFile {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SourceFile")
|
||||
.field("path", &self.path())
|
||||
.field("is_real", &self.is_real())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
impl PartialEq for SourceFile {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0.eq(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
impl Eq for SourceFile {}
|
||||
|
||||
/// A single token or a delimited sequence of token trees (e.g., `[1, (), ..]`).
|
||||
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
|
||||
#[derive(Clone)]
|
||||
|
|
|
@ -1286,6 +1286,40 @@ pub struct Output {
|
|||
pub stderr: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Output {
|
||||
/// Returns an error if a nonzero exit status was received.
|
||||
///
|
||||
/// If the [`Command`] exited successfully,
|
||||
/// `self` is returned.
|
||||
///
|
||||
/// This is equivalent to calling [`exit_ok`](ExitStatus::exit_ok)
|
||||
/// on [`Output.status`](Output::status).
|
||||
///
|
||||
/// Note that this will throw away the [`Output::stderr`] field in the error case.
|
||||
/// If the child process outputs useful informantion to stderr, you can:
|
||||
/// * Use `cmd.stderr(Stdio::inherit())` to forward the
|
||||
/// stderr child process to the parent's stderr,
|
||||
/// usually printing it to console where the user can see it.
|
||||
/// This is usually correct for command-line applications.
|
||||
/// * Capture `stderr` using a custom error type.
|
||||
/// This is usually correct for libraries.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(exit_status_error)]
|
||||
/// # #[cfg(unix)] {
|
||||
/// use std::process::Command;
|
||||
/// assert!(Command::new("false").output().unwrap().exit_ok().is_err());
|
||||
/// # }
|
||||
/// ```
|
||||
#[unstable(feature = "exit_status_error", issue = "84908")]
|
||||
pub fn exit_ok(self) -> Result<Self, ExitStatusError> {
|
||||
self.status.exit_ok()?;
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
// If either stderr or stdout are valid utf8 strings it prints the valid
|
||||
// strings, otherwise it prints the byte sequence instead
|
||||
#[stable(feature = "process_output_debug", since = "1.7.0")]
|
||||
|
|
|
@ -274,6 +274,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
|
|||
libc::ETXTBSY => ExecutableFileBusy,
|
||||
libc::EXDEV => CrossesDevices,
|
||||
libc::EINPROGRESS => InProgress,
|
||||
libc::EOPNOTSUPP => Unsupported,
|
||||
|
||||
libc::EACCES | libc::EPERM => PermissionDenied,
|
||||
|
||||
|
|
|
@ -8,14 +8,19 @@ use crate::sys::weak::weak;
|
|||
use crate::sys::{os, stack_overflow};
|
||||
use crate::time::Duration;
|
||||
use crate::{cmp, io, ptr};
|
||||
#[cfg(not(any(target_os = "l4re", target_os = "vxworks", target_os = "espidf")))]
|
||||
#[cfg(not(any(
|
||||
target_os = "l4re",
|
||||
target_os = "vxworks",
|
||||
target_os = "espidf",
|
||||
target_os = "nuttx"
|
||||
)))]
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
|
||||
#[cfg(target_os = "l4re")]
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
|
||||
#[cfg(target_os = "vxworks")]
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 256 * 1024;
|
||||
#[cfg(target_os = "espidf")]
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF menuconfig system should be used
|
||||
#[cfg(any(target_os = "espidf", target_os = "nuttx"))]
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF/NuttX menuconfig system should be used
|
||||
|
||||
#[cfg(target_os = "fuchsia")]
|
||||
mod zircon {
|
||||
|
@ -52,10 +57,10 @@ impl Thread {
|
|||
let mut attr: mem::MaybeUninit<libc::pthread_attr_t> = mem::MaybeUninit::uninit();
|
||||
assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0);
|
||||
|
||||
#[cfg(target_os = "espidf")]
|
||||
#[cfg(any(target_os = "espidf", target_os = "nuttx"))]
|
||||
if stack > 0 {
|
||||
// Only set the stack if a non-zero value is passed
|
||||
// 0 is used as an indication that the default stack size configured in the ESP-IDF menuconfig system should be used
|
||||
// 0 is used as an indication that the default stack size configured in the ESP-IDF/NuttX menuconfig system should be used
|
||||
assert_eq!(
|
||||
libc::pthread_attr_setstacksize(
|
||||
attr.as_mut_ptr(),
|
||||
|
@ -65,7 +70,7 @@ impl Thread {
|
|||
);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "espidf"))]
|
||||
#[cfg(not(any(target_os = "espidf", target_os = "nuttx")))]
|
||||
{
|
||||
let stack_size = cmp::max(stack, min_stack_size(attr.as_ptr()));
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use r_efi::protocols::simple_text_output;
|
||||
use r_efi::protocols::{simple_text_input, simple_text_output};
|
||||
|
||||
use crate::collections::BTreeMap;
|
||||
pub use crate::ffi::OsString as EnvKey;
|
||||
|
@ -23,6 +23,7 @@ pub struct Command {
|
|||
args: Vec<OsString>,
|
||||
stdout: Option<Stdio>,
|
||||
stderr: Option<Stdio>,
|
||||
stdin: Option<Stdio>,
|
||||
env: CommandEnv,
|
||||
}
|
||||
|
||||
|
@ -48,6 +49,7 @@ impl Command {
|
|||
args: Vec::new(),
|
||||
stdout: None,
|
||||
stderr: None,
|
||||
stdin: None,
|
||||
env: Default::default(),
|
||||
}
|
||||
}
|
||||
|
@ -64,8 +66,8 @@ impl Command {
|
|||
panic!("unsupported")
|
||||
}
|
||||
|
||||
pub fn stdin(&mut self, _stdin: Stdio) {
|
||||
panic!("unsupported")
|
||||
pub fn stdin(&mut self, stdin: Stdio) {
|
||||
self.stdin = Some(stdin);
|
||||
}
|
||||
|
||||
pub fn stdout(&mut self, stdout: Stdio) {
|
||||
|
@ -122,6 +124,22 @@ impl Command {
|
|||
}
|
||||
}
|
||||
|
||||
fn create_stdin(
|
||||
s: Stdio,
|
||||
) -> io::Result<Option<helpers::OwnedProtocol<uefi_command_internal::InputProtocol>>> {
|
||||
match s {
|
||||
Stdio::Null => unsafe {
|
||||
helpers::OwnedProtocol::create(
|
||||
uefi_command_internal::InputProtocol::null(),
|
||||
simple_text_input::PROTOCOL_GUID,
|
||||
)
|
||||
}
|
||||
.map(Some),
|
||||
Stdio::Inherit => Ok(None),
|
||||
Stdio::MakePipe => unsupported(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
|
||||
let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?;
|
||||
|
||||
|
@ -149,6 +167,15 @@ impl Command {
|
|||
cmd.stderr_inherit()
|
||||
};
|
||||
|
||||
// Setup Stdin
|
||||
let stdin = self.stdin.unwrap_or(Stdio::Null);
|
||||
let stdin = Self::create_stdin(stdin)?;
|
||||
if let Some(con) = stdin {
|
||||
cmd.stdin_init(con)
|
||||
} else {
|
||||
cmd.stdin_inherit()
|
||||
};
|
||||
|
||||
let env = env_changes(&self.env);
|
||||
|
||||
// Set any new vars
|
||||
|
@ -334,7 +361,7 @@ impl<'a> fmt::Debug for CommandArgs<'a> {
|
|||
|
||||
#[allow(dead_code)]
|
||||
mod uefi_command_internal {
|
||||
use r_efi::protocols::{loaded_image, simple_text_output};
|
||||
use r_efi::protocols::{loaded_image, simple_text_input, simple_text_output};
|
||||
|
||||
use crate::ffi::{OsStr, OsString};
|
||||
use crate::io::{self, const_error};
|
||||
|
@ -350,6 +377,7 @@ mod uefi_command_internal {
|
|||
handle: NonNull<crate::ffi::c_void>,
|
||||
stdout: Option<helpers::OwnedProtocol<PipeProtocol>>,
|
||||
stderr: Option<helpers::OwnedProtocol<PipeProtocol>>,
|
||||
stdin: Option<helpers::OwnedProtocol<InputProtocol>>,
|
||||
st: OwnedTable<r_efi::efi::SystemTable>,
|
||||
args: Option<(*mut u16, usize)>,
|
||||
}
|
||||
|
@ -384,7 +412,14 @@ mod uefi_command_internal {
|
|||
helpers::open_protocol(child_handle, loaded_image::PROTOCOL_GUID).unwrap();
|
||||
let st = OwnedTable::from_table(unsafe { (*loaded_image.as_ptr()).system_table });
|
||||
|
||||
Ok(Self { handle: child_handle, stdout: None, stderr: None, st, args: None })
|
||||
Ok(Self {
|
||||
handle: child_handle,
|
||||
stdout: None,
|
||||
stderr: None,
|
||||
stdin: None,
|
||||
st,
|
||||
args: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -445,6 +480,17 @@ mod uefi_command_internal {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_stdin(
|
||||
&mut self,
|
||||
handle: r_efi::efi::Handle,
|
||||
protocol: *mut simple_text_input::Protocol,
|
||||
) {
|
||||
unsafe {
|
||||
(*self.st.as_mut_ptr()).console_in_handle = handle;
|
||||
(*self.st.as_mut_ptr()).con_in = protocol;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stdout_init(&mut self, protocol: helpers::OwnedProtocol<PipeProtocol>) {
|
||||
self.set_stdout(
|
||||
protocol.handle().as_ptr(),
|
||||
|
@ -471,6 +517,19 @@ mod uefi_command_internal {
|
|||
unsafe { self.set_stderr((*st.as_ptr()).standard_error_handle, (*st.as_ptr()).std_err) }
|
||||
}
|
||||
|
||||
pub(crate) fn stdin_init(&mut self, protocol: helpers::OwnedProtocol<InputProtocol>) {
|
||||
self.set_stdin(
|
||||
protocol.handle().as_ptr(),
|
||||
protocol.as_ref() as *const InputProtocol as *mut simple_text_input::Protocol,
|
||||
);
|
||||
self.stdin = Some(protocol);
|
||||
}
|
||||
|
||||
pub(crate) fn stdin_inherit(&mut self) {
|
||||
let st: NonNull<r_efi::efi::SystemTable> = system_table().cast();
|
||||
unsafe { self.set_stdin((*st.as_ptr()).console_in_handle, (*st.as_ptr()).con_in) }
|
||||
}
|
||||
|
||||
pub fn stderr(&self) -> io::Result<Vec<u8>> {
|
||||
match &self.stderr {
|
||||
Some(stderr) => stderr.as_ref().utf8(),
|
||||
|
@ -722,6 +781,56 @@ mod uefi_command_internal {
|
|||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub(crate) struct InputProtocol {
|
||||
reset: simple_text_input::ProtocolReset,
|
||||
read_key_stroke: simple_text_input::ProtocolReadKeyStroke,
|
||||
wait_for_key: r_efi::efi::Event,
|
||||
}
|
||||
|
||||
impl InputProtocol {
|
||||
pub(crate) fn null() -> Self {
|
||||
let evt = helpers::OwnedEvent::new(
|
||||
r_efi::efi::EVT_NOTIFY_WAIT,
|
||||
r_efi::efi::TPL_CALLBACK,
|
||||
Some(Self::empty_notify),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Self {
|
||||
reset: Self::null_reset,
|
||||
read_key_stroke: Self::null_read_key,
|
||||
wait_for_key: evt.into_raw(),
|
||||
}
|
||||
}
|
||||
|
||||
extern "efiapi" fn null_reset(
|
||||
_: *mut simple_text_input::Protocol,
|
||||
_: r_efi::efi::Boolean,
|
||||
) -> r_efi::efi::Status {
|
||||
r_efi::efi::Status::SUCCESS
|
||||
}
|
||||
|
||||
extern "efiapi" fn null_read_key(
|
||||
_: *mut simple_text_input::Protocol,
|
||||
_: *mut simple_text_input::InputKey,
|
||||
) -> r_efi::efi::Status {
|
||||
r_efi::efi::Status::UNSUPPORTED
|
||||
}
|
||||
|
||||
extern "efiapi" fn empty_notify(_: r_efi::efi::Event, _: *mut crate::ffi::c_void) {}
|
||||
}
|
||||
|
||||
impl Drop for InputProtocol {
|
||||
fn drop(&mut self) {
|
||||
// Close wait_for_key
|
||||
unsafe {
|
||||
let _ = helpers::OwnedEvent::from_raw(self.wait_for_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> {
|
||||
const QUOTE: u16 = 0x0022;
|
||||
const SPACE: u16 = 0x0020;
|
||||
|
|
|
@ -142,8 +142,12 @@ impl io::Write for Stderr {
|
|||
// UTF-16 character should occupy 4 bytes at most in UTF-8
|
||||
pub const STDIN_BUF_SIZE: usize = 4;
|
||||
|
||||
pub fn is_ebadf(_err: &io::Error) -> bool {
|
||||
false
|
||||
pub fn is_ebadf(err: &io::Error) -> bool {
|
||||
if let Some(x) = err.raw_os_error() {
|
||||
r_efi::efi::Status::UNSUPPORTED.as_usize() == x
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn panic_output() -> Option<impl io::Write> {
|
||||
|
|
|
@ -63,6 +63,24 @@ fn smoke_port_gone() {
|
|||
assert!(tx.send(1).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn smoke_receiver_clone() {
|
||||
let (tx, rx) = channel::<i32>();
|
||||
let rx2 = rx.clone();
|
||||
drop(rx);
|
||||
tx.send(1).unwrap();
|
||||
assert_eq!(rx2.recv().unwrap(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn smoke_receiver_clone_port_gone() {
|
||||
let (tx, rx) = channel::<i32>();
|
||||
let rx2 = rx.clone();
|
||||
drop(rx);
|
||||
drop(rx2);
|
||||
assert!(tx.send(1).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn smoke_shared_port_gone() {
|
||||
let (tx, rx) = channel::<i32>();
|
||||
|
@ -124,6 +142,18 @@ fn chan_gone_concurrent() {
|
|||
while rx.recv().is_ok() {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn receiver_cloning() {
|
||||
let (tx, rx) = channel::<i32>();
|
||||
let rx2 = rx.clone();
|
||||
|
||||
tx.send(1).unwrap();
|
||||
tx.send(2).unwrap();
|
||||
|
||||
assert_eq!(rx2.recv(), Ok(1));
|
||||
assert_eq!(rx.recv(), Ok(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stress() {
|
||||
let count = if cfg!(miri) { 100 } else { 10000 };
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue