Merge ref '2a9bacf618' from rust-lang/rust
Pull recent changes from https://github.com/rust-lang/rust via Josh. Upstream ref:2a9bacf618Filtered ref: d7fc6d06166167894862d54c9618a3cd7599fa9c Upstream diff:f4665ab836...2a9bacf618This merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
commit
7bc4a3be4c
96 changed files with 1503 additions and 1661 deletions
|
|
@ -1,8 +1,8 @@
|
|||
mod context;
|
||||
|
||||
use rustc_ast::token::{self, Delimiter};
|
||||
use rustc_ast::token::Delimiter;
|
||||
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
|
||||
use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment};
|
||||
use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp, token};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
|
||||
|
|
@ -29,7 +29,7 @@ pub(crate) fn expand_assert<'cx>(
|
|||
|
||||
// `core::panic` and `std::panic` are different macros, so we use call-site
|
||||
// context to pick up whichever is currently in scope.
|
||||
let call_site_span = cx.with_call_site_ctxt(cond_expr.span);
|
||||
let call_site_span = cx.with_call_site_ctxt(span);
|
||||
|
||||
let panic_path = || {
|
||||
if use_panic_2021(span) {
|
||||
|
|
@ -63,7 +63,7 @@ pub(crate) fn expand_assert<'cx>(
|
|||
}),
|
||||
})),
|
||||
);
|
||||
assert_cond_check(cx, call_site_span, cond_expr, then)
|
||||
expr_if_not(cx, call_site_span, cond_expr, then, None)
|
||||
}
|
||||
// If `generic_assert` is enabled, generates rich captured outputs
|
||||
//
|
||||
|
|
@ -88,33 +88,26 @@ pub(crate) fn expand_assert<'cx>(
|
|||
)),
|
||||
)],
|
||||
);
|
||||
assert_cond_check(cx, call_site_span, cond_expr, then)
|
||||
expr_if_not(cx, call_site_span, cond_expr, then, None)
|
||||
};
|
||||
|
||||
ExpandResult::Ready(MacEager::expr(expr))
|
||||
}
|
||||
|
||||
/// `assert!($cond_expr, $custom_message)`
|
||||
struct Assert {
|
||||
cond_expr: Box<Expr>,
|
||||
custom_message: Option<TokenStream>,
|
||||
}
|
||||
|
||||
/// `match <cond> { true => {} _ => <then> }`
|
||||
fn assert_cond_check(cx: &ExtCtxt<'_>, span: Span, cond: Box<Expr>, then: Box<Expr>) -> Box<Expr> {
|
||||
// Instead of expanding to `if !<cond> { <then> }`, we expand to
|
||||
// `match <cond> { true => {} _ => <then> }`.
|
||||
// This allows us to always complain about mismatched types instead of "cannot apply unary
|
||||
// operator `!` to type `X`" when passing an invalid `<cond>`, while also allowing `<cond>` to
|
||||
// be `&true`.
|
||||
let els = cx.expr_block(cx.block(span, thin_vec![]));
|
||||
let mut arms = thin_vec![];
|
||||
arms.push(cx.arm(span, cx.pat_lit(span, cx.expr_bool(span, true)), els));
|
||||
arms.push(cx.arm(span, cx.pat_wild(span), then));
|
||||
|
||||
// We wrap the `match` in a statement to limit the length of any borrows introduced in the
|
||||
// condition.
|
||||
cx.expr_block(cx.block(span, [cx.stmt_expr(cx.expr_match(span, cond, arms))].into()))
|
||||
// if !{ ... } { ... } else { ... }
|
||||
fn expr_if_not(
|
||||
cx: &ExtCtxt<'_>,
|
||||
span: Span,
|
||||
cond: Box<Expr>,
|
||||
then: Box<Expr>,
|
||||
els: Option<Box<Expr>>,
|
||||
) -> Box<Expr> {
|
||||
cx.expr_if(span, cx.expr(span, ExprKind::Unary(UnOp::Not, cond)), then, els)
|
||||
}
|
||||
|
||||
fn parse_assert<'a>(cx: &ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> {
|
||||
|
|
|
|||
|
|
@ -92,10 +92,10 @@ fn can_continue_type_after_non_fn_ident(t: &Token) -> bool {
|
|||
}
|
||||
|
||||
fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool {
|
||||
// `Not`, `Tilde` & `Const` are deliberately not part of this list to
|
||||
// `!`, `const`, `[`, `async` are deliberately not part of this list to
|
||||
// contain the number of potential regressions esp. in MBE code.
|
||||
// `Const` would regress `rfc-2632-const-trait-impl/mbe-dyn-const-2015.rs`.
|
||||
// `Not` would regress `dyn!(...)` macro calls in Rust 2015.
|
||||
// `const` and `[` would regress UI test `macro-dyn-const-2015.rs`.
|
||||
// `!` would regress `dyn!(...)` macro calls in Rust 2015.
|
||||
t.is_path_start()
|
||||
|| t.is_lifetime()
|
||||
|| t == &TokenKind::Question
|
||||
|
|
@ -1015,12 +1015,18 @@ impl<'a> Parser<'a> {
|
|||
|| self.check(exp!(Tilde))
|
||||
|| self.check_keyword(exp!(For))
|
||||
|| self.check(exp!(OpenParen))
|
||||
|| self.check(exp!(OpenBracket))
|
||||
|| self.can_begin_maybe_const_bound()
|
||||
|| self.check_keyword(exp!(Const))
|
||||
|| self.check_keyword(exp!(Async))
|
||||
|| self.check_keyword(exp!(Use))
|
||||
}
|
||||
|
||||
fn can_begin_maybe_const_bound(&mut self) -> bool {
|
||||
self.check(exp!(OpenBracket))
|
||||
&& self.look_ahead(1, |t| t.is_keyword(kw::Const))
|
||||
&& self.look_ahead(2, |t| *t == token::CloseBracket)
|
||||
}
|
||||
|
||||
/// Parse a bound.
|
||||
///
|
||||
/// ```ebnf
|
||||
|
|
@ -1199,10 +1205,7 @@ impl<'a> Parser<'a> {
|
|||
let span = tilde.to(self.prev_token.span);
|
||||
self.psess.gated_spans.gate(sym::const_trait_impl, span);
|
||||
BoundConstness::Maybe(span)
|
||||
} else if self.check(exp!(OpenBracket))
|
||||
&& self.look_ahead(1, |t| t.is_keyword(kw::Const))
|
||||
&& self.look_ahead(2, |t| *t == token::CloseBracket)
|
||||
{
|
||||
} else if self.can_begin_maybe_const_bound() {
|
||||
let start = self.token.span;
|
||||
self.bump();
|
||||
self.expect_keyword(exp!(Const)).unwrap();
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use std::ops::Deref;
|
|||
use std::{fmt, str};
|
||||
|
||||
use rustc_arena::DroplessArena;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
|
||||
use rustc_data_structures::stable_hasher::{
|
||||
HashStable, StableCompare, StableHasher, ToStableHashKey,
|
||||
};
|
||||
|
|
@ -2871,11 +2871,20 @@ impl Interner {
|
|||
let byte_strs = FxIndexSet::from_iter(
|
||||
init.iter().copied().chain(extra.iter().copied()).map(|str| str.as_bytes()),
|
||||
);
|
||||
assert_eq!(
|
||||
byte_strs.len(),
|
||||
init.len() + extra.len(),
|
||||
"duplicate symbols in the rustc symbol list and the extra symbols added by the driver",
|
||||
);
|
||||
|
||||
// The order in which duplicates are reported is irrelevant.
|
||||
#[expect(rustc::potential_query_instability)]
|
||||
if byte_strs.len() != init.len() + extra.len() {
|
||||
panic!(
|
||||
"duplicate symbols in the rustc symbol list and the extra symbols added by the driver: {:?}",
|
||||
FxHashSet::intersection(
|
||||
&init.iter().copied().collect(),
|
||||
&extra.iter().copied().collect(),
|
||||
)
|
||||
.collect::<Vec<_>>()
|
||||
)
|
||||
}
|
||||
|
||||
Interner(Lock::new(InternerInner { arena: Default::default(), byte_strs }))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -849,6 +849,7 @@ const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
|||
("miscellaneous-extensions-3", Unstable(sym::s390x_target_feature), &[]),
|
||||
("miscellaneous-extensions-4", Unstable(sym::s390x_target_feature), &[]),
|
||||
("nnp-assist", Unstable(sym::s390x_target_feature), &["vector"]),
|
||||
("soft-float", Forbidden { reason: "currently unsupported ABI-configuration feature" }, &[]),
|
||||
("transactional-execution", Unstable(sym::s390x_target_feature), &[]),
|
||||
("vector", Unstable(sym::s390x_target_feature), &[]),
|
||||
("vector-enhancements-1", Unstable(sym::s390x_target_feature), &["vector"]),
|
||||
|
|
@ -1177,6 +1178,13 @@ impl Target {
|
|||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
"s390x" => {
|
||||
// We don't currently support a softfloat target on this architecture.
|
||||
// As usual, we have to reject swapping the `soft-float` target feature.
|
||||
// The "vector" target feature does not affect the ABI for floats
|
||||
// because the vector and float registers overlap.
|
||||
FeatureConstraints { required: &[], incompatible: &["soft-float"] }
|
||||
}
|
||||
_ => NOTHING,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1618,18 +1618,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
{
|
||||
let e = self.tcx.erase_and_anonymize_regions(e);
|
||||
let f = self.tcx.erase_and_anonymize_regions(f);
|
||||
let mut expected = with_forced_trimmed_paths!(e.sort_string(self.tcx));
|
||||
let mut found = with_forced_trimmed_paths!(f.sort_string(self.tcx));
|
||||
if let ObligationCauseCode::Pattern { span, .. } = cause.code()
|
||||
&& let Some(span) = span
|
||||
&& !span.from_expansion()
|
||||
&& cause.span.from_expansion()
|
||||
{
|
||||
// When the type error comes from a macro like `assert!()`, and we are pointing at
|
||||
// code the user wrote the cause and effect are reversed as the expected value is
|
||||
// what the macro expanded to.
|
||||
(found, expected) = (expected, found);
|
||||
}
|
||||
let expected = with_forced_trimmed_paths!(e.sort_string(self.tcx));
|
||||
let found = with_forced_trimmed_paths!(f.sort_string(self.tcx));
|
||||
if expected == found {
|
||||
label_or_note(span, terr.to_string(self.tcx));
|
||||
} else {
|
||||
|
|
@ -2152,9 +2142,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
) -> Option<(DiagStyledString, DiagStyledString)> {
|
||||
match values {
|
||||
ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found),
|
||||
ValuePairs::Terms(exp_found) => {
|
||||
self.expected_found_str_term(cause, exp_found, long_ty_path)
|
||||
}
|
||||
ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found, long_ty_path),
|
||||
ValuePairs::Aliases(exp_found) => self.expected_found_str(exp_found),
|
||||
ValuePairs::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found),
|
||||
ValuePairs::ExistentialProjection(exp_found) => self.expected_found_str(exp_found),
|
||||
|
|
@ -2193,7 +2181,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
|
||||
fn expected_found_str_term(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
exp_found: ty::error::ExpectedFound<ty::Term<'tcx>>,
|
||||
long_ty_path: &mut Option<PathBuf>,
|
||||
) -> Option<(DiagStyledString, DiagStyledString)> {
|
||||
|
|
@ -2201,27 +2188,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
if exp_found.references_error() {
|
||||
return None;
|
||||
}
|
||||
let (mut expected, mut found) = (exp_found.expected, exp_found.found);
|
||||
|
||||
if let ObligationCauseCode::Pattern { span, .. } = cause.code()
|
||||
&& let Some(span) = span
|
||||
&& !span.from_expansion()
|
||||
&& cause.span.from_expansion()
|
||||
{
|
||||
// When the type error comes from a macro like `assert!()`, and we are pointing at
|
||||
// code the user wrote, the cause and effect are reversed as the expected value is
|
||||
// what the macro expanded to. So if the user provided a `Type` when the macro is
|
||||
// written in such a way that a `bool` was expected, we want to print:
|
||||
// = note: expected `bool`
|
||||
// found `Type`"
|
||||
// but as far as the compiler is concerned, after expansion what was expected was `Type`
|
||||
// = note: expected `Type`
|
||||
// found `bool`"
|
||||
// so we reverse them here to match user expectation.
|
||||
(expected, found) = (found, expected);
|
||||
}
|
||||
|
||||
Some(match (expected.kind(), found.kind()) {
|
||||
Some(match (exp_found.expected.kind(), exp_found.found.kind()) {
|
||||
(ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => {
|
||||
let (mut exp, mut fnd) = self.cmp(expected, found);
|
||||
// Use the terminal width as the basis to determine when to compress the printed
|
||||
|
|
|
|||
|
|
@ -146,28 +146,7 @@ impl<T: PointeeSized> *const T {
|
|||
self as _
|
||||
}
|
||||
|
||||
/// Gets the "address" portion of the pointer.
|
||||
///
|
||||
/// This is similar to `self as usize`, except that the [provenance][crate::ptr#provenance] of
|
||||
/// the pointer is discarded and not [exposed][crate::ptr#exposed-provenance]. This means that
|
||||
/// casting the returned address back to a pointer yields a [pointer without
|
||||
/// provenance][without_provenance], which is undefined behavior to dereference. To properly
|
||||
/// restore the lost information and obtain a dereferenceable pointer, use
|
||||
/// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr].
|
||||
///
|
||||
/// If using those APIs is not possible because there is no way to preserve a pointer with the
|
||||
/// required provenance, then Strict Provenance might not be for you. Use pointer-integer casts
|
||||
/// or [`expose_provenance`][pointer::expose_provenance] and [`with_exposed_provenance`][with_exposed_provenance]
|
||||
/// instead. However, note that this makes your code less portable and less amenable to tools
|
||||
/// that check for compliance with the Rust memory model.
|
||||
///
|
||||
/// On most platforms this will produce a value with the same bytes as the original
|
||||
/// pointer, because all the bytes are dedicated to describing the address.
|
||||
/// Platforms which need to store additional information in the pointer may
|
||||
/// perform a change of representation to produce a value containing only the address
|
||||
/// portion of the pointer. What that means is up to the platform to define.
|
||||
///
|
||||
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
|
||||
#[doc = include_str!("./docs/addr.md")]
|
||||
#[must_use]
|
||||
#[inline(always)]
|
||||
#[stable(feature = "strict_provenance", since = "1.84.0")]
|
||||
|
|
@ -254,23 +233,16 @@ impl<T: PointeeSized> *const T {
|
|||
(self.cast(), metadata(self))
|
||||
}
|
||||
|
||||
/// Returns `None` if the pointer is null, or else returns a shared reference to
|
||||
/// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_ref`]
|
||||
/// must be used instead.
|
||||
#[doc = include_str!("./docs/as_ref.md")]
|
||||
///
|
||||
/// [`as_uninit_ref`]: #method.as_uninit_ref
|
||||
/// ```
|
||||
/// let ptr: *const u8 = &10u8 as *const u8;
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// When calling this method, you have to ensure that *either* the pointer is null *or*
|
||||
/// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion).
|
||||
///
|
||||
/// # Panics during const evaluation
|
||||
///
|
||||
/// This method will panic during const evaluation if the pointer cannot be
|
||||
/// determined to be null or not. See [`is_null`] for more information.
|
||||
///
|
||||
/// [`is_null`]: #method.is_null
|
||||
/// unsafe {
|
||||
/// let val_back = &*ptr;
|
||||
/// assert_eq!(val_back, &10);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -284,20 +256,9 @@ impl<T: PointeeSized> *const T {
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Null-unchecked version
|
||||
///
|
||||
/// If you are sure the pointer can never be null and are looking for some kind of
|
||||
/// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>`, know that you can
|
||||
/// dereference the pointer directly.
|
||||
///
|
||||
/// ```
|
||||
/// let ptr: *const u8 = &10u8 as *const u8;
|
||||
///
|
||||
/// unsafe {
|
||||
/// let val_back = &*ptr;
|
||||
/// assert_eq!(val_back, &10);
|
||||
/// }
|
||||
/// ```
|
||||
/// [`is_null`]: #method.is_null
|
||||
/// [`as_uninit_ref`]: #method.as_uninit_ref
|
||||
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
|
||||
#[rustc_const_stable(feature = "const_ptr_is_null", since = "1.84.0")]
|
||||
#[inline]
|
||||
|
|
@ -338,23 +299,10 @@ impl<T: PointeeSized> *const T {
|
|||
unsafe { &*self }
|
||||
}
|
||||
|
||||
/// Returns `None` if the pointer is null, or else returns a shared reference to
|
||||
/// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require
|
||||
/// that the value has to be initialized.
|
||||
///
|
||||
/// [`as_ref`]: #method.as_ref
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// When calling this method, you have to ensure that *either* the pointer is null *or*
|
||||
/// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion).
|
||||
///
|
||||
/// # Panics during const evaluation
|
||||
///
|
||||
/// This method will panic during const evaluation if the pointer cannot be
|
||||
/// determined to be null or not. See [`is_null`] for more information.
|
||||
#[doc = include_str!("./docs/as_uninit_ref.md")]
|
||||
///
|
||||
/// [`is_null`]: #method.is_null
|
||||
/// [`as_ref`]: #method.as_ref
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
|||
21
library/core/src/ptr/docs/INFO.md
Normal file
21
library/core/src/ptr/docs/INFO.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
This directory holds method documentation that otherwise
|
||||
would be duplicated across mutable and immutable pointers.
|
||||
|
||||
Note that most of the docs here are not the complete docs
|
||||
for their corresponding method. This is for a few reasons:
|
||||
|
||||
1. Examples need to be different for mutable/immutable
|
||||
pointers, in order to actually call the correct method.
|
||||
2. Link reference definitions are frequently different
|
||||
between mutable/immutable pointers, in order to link to
|
||||
the correct method.
|
||||
For example, `<*const T>::as_ref` links to
|
||||
`<*const T>::is_null`, while `<*mut T>::as_ref` links to
|
||||
`<*mut T>::is_null`.
|
||||
3. Many methods on mutable pointers link to an alternate
|
||||
version that returns a mutable reference instead of
|
||||
a shared reference.
|
||||
|
||||
Always review the rendered docs manually when making
|
||||
changes to these files to make sure you're not accidentally
|
||||
splitting up a section.
|
||||
22
library/core/src/ptr/docs/addr.md
Normal file
22
library/core/src/ptr/docs/addr.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
Gets the "address" portion of the pointer.
|
||||
|
||||
This is similar to `self as usize`, except that the [provenance][crate::ptr#provenance] of
|
||||
the pointer is discarded and not [exposed][crate::ptr#exposed-provenance]. This means that
|
||||
casting the returned address back to a pointer yields a [pointer without
|
||||
provenance][without_provenance], which is undefined behavior to dereference. To properly
|
||||
restore the lost information and obtain a dereferenceable pointer, use
|
||||
[`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr].
|
||||
|
||||
If using those APIs is not possible because there is no way to preserve a pointer with the
|
||||
required provenance, then Strict Provenance might not be for you. Use pointer-integer casts
|
||||
or [`expose_provenance`][pointer::expose_provenance] and [`with_exposed_provenance`][with_exposed_provenance]
|
||||
instead. However, note that this makes your code less portable and less amenable to tools
|
||||
that check for compliance with the Rust memory model.
|
||||
|
||||
On most platforms this will produce a value with the same bytes as the original
|
||||
pointer, because all the bytes are dedicated to describing the address.
|
||||
Platforms which need to store additional information in the pointer may
|
||||
perform a change of representation to produce a value containing only the address
|
||||
portion of the pointer. What that means is up to the platform to define.
|
||||
|
||||
This is a [Strict Provenance][crate::ptr#strict-provenance] API.
|
||||
19
library/core/src/ptr/docs/as_ref.md
Normal file
19
library/core/src/ptr/docs/as_ref.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Returns `None` if the pointer is null, or else returns a shared reference to
|
||||
the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_ref`]
|
||||
must be used instead.
|
||||
|
||||
# Safety
|
||||
|
||||
When calling this method, you have to ensure that *either* the pointer is null *or*
|
||||
the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion).
|
||||
|
||||
# Panics during const evaluation
|
||||
|
||||
This method will panic during const evaluation if the pointer cannot be
|
||||
determined to be null or not. See [`is_null`] for more information.
|
||||
|
||||
# Null-unchecked version
|
||||
|
||||
If you are sure the pointer can never be null and are looking for some kind of
|
||||
`as_ref_unchecked` that returns the `&T` instead of `Option<&T>`, know that you can
|
||||
dereference the pointer directly.
|
||||
15
library/core/src/ptr/docs/as_uninit_ref.md
Normal file
15
library/core/src/ptr/docs/as_uninit_ref.md
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
Returns `None` if the pointer is null, or else returns a shared reference to
|
||||
the value wrapped in `Some`. In contrast to [`as_ref`], this does not require
|
||||
that the value has to be initialized.
|
||||
|
||||
# Safety
|
||||
|
||||
When calling this method, you have to ensure that *either* the pointer is null *or*
|
||||
the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion).
|
||||
Note that because the created reference is to `MaybeUninit<T>`, the
|
||||
source pointer can point to uninitialized memory.
|
||||
|
||||
# Panics during const evaluation
|
||||
|
||||
This method will panic during const evaluation if the pointer cannot be
|
||||
determined to be null or not. See [`is_null`] for more information.
|
||||
|
|
@ -135,28 +135,9 @@ impl<T: PointeeSized> *mut T {
|
|||
self as _
|
||||
}
|
||||
|
||||
/// Gets the "address" portion of the pointer.
|
||||
#[doc = include_str!("./docs/addr.md")]
|
||||
///
|
||||
/// This is similar to `self as usize`, except that the [provenance][crate::ptr#provenance] of
|
||||
/// the pointer is discarded and not [exposed][crate::ptr#exposed-provenance]. This means that
|
||||
/// casting the returned address back to a pointer yields a [pointer without
|
||||
/// provenance][without_provenance_mut], which is undefined behavior to dereference. To properly
|
||||
/// restore the lost information and obtain a dereferenceable pointer, use
|
||||
/// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr].
|
||||
///
|
||||
/// If using those APIs is not possible because there is no way to preserve a pointer with the
|
||||
/// required provenance, then Strict Provenance might not be for you. Use pointer-integer casts
|
||||
/// or [`expose_provenance`][pointer::expose_provenance] and [`with_exposed_provenance`][with_exposed_provenance]
|
||||
/// instead. However, note that this makes your code less portable and less amenable to tools
|
||||
/// that check for compliance with the Rust memory model.
|
||||
///
|
||||
/// On most platforms this will produce a value with the same bytes as the original
|
||||
/// pointer, because all the bytes are dedicated to describing the address.
|
||||
/// Platforms which need to store additional information in the pointer may
|
||||
/// perform a change of representation to produce a value containing only the address
|
||||
/// portion of the pointer. What that means is up to the platform to define.
|
||||
///
|
||||
/// This is a [Strict Provenance][crate::ptr#strict-provenance] API.
|
||||
/// [without_provenance]: without_provenance_mut
|
||||
#[must_use]
|
||||
#[inline(always)]
|
||||
#[stable(feature = "strict_provenance", since = "1.84.0")]
|
||||
|
|
@ -243,26 +224,16 @@ impl<T: PointeeSized> *mut T {
|
|||
(self.cast(), super::metadata(self))
|
||||
}
|
||||
|
||||
/// Returns `None` if the pointer is null, or else returns a shared reference to
|
||||
/// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_ref`]
|
||||
/// must be used instead.
|
||||
#[doc = include_str!("./docs/as_ref.md")]
|
||||
///
|
||||
/// For the mutable counterpart see [`as_mut`].
|
||||
/// ```
|
||||
/// let ptr: *mut u8 = &mut 10u8 as *mut u8;
|
||||
///
|
||||
/// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1
|
||||
/// [`as_mut`]: #method.as_mut
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// When calling this method, you have to ensure that *either* the pointer is null *or*
|
||||
/// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion).
|
||||
///
|
||||
/// # Panics during const evaluation
|
||||
///
|
||||
/// This method will panic during const evaluation if the pointer cannot be
|
||||
/// determined to be null or not. See [`is_null`] for more information.
|
||||
///
|
||||
/// [`is_null`]: #method.is_null-1
|
||||
/// unsafe {
|
||||
/// let val_back = &*ptr;
|
||||
/// println!("We got back the value: {val_back}!");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -276,20 +247,14 @@ impl<T: PointeeSized> *mut T {
|
|||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Null-unchecked version
|
||||
/// # See Also
|
||||
///
|
||||
/// If you are sure the pointer can never be null and are looking for some kind of
|
||||
/// `as_ref_unchecked` that returns the `&T` instead of `Option<&T>`, know that you can
|
||||
/// dereference the pointer directly.
|
||||
/// For the mutable counterpart see [`as_mut`].
|
||||
///
|
||||
/// ```
|
||||
/// let ptr: *mut u8 = &mut 10u8 as *mut u8;
|
||||
///
|
||||
/// unsafe {
|
||||
/// let val_back = &*ptr;
|
||||
/// println!("We got back the value: {val_back}!");
|
||||
/// }
|
||||
/// ```
|
||||
/// [`is_null`]: #method.is_null-1
|
||||
/// [`as_uninit_ref`]: pointer#method.as_uninit_ref-1
|
||||
/// [`as_mut`]: #method.as_mut
|
||||
|
||||
#[stable(feature = "ptr_as_ref", since = "1.9.0")]
|
||||
#[rustc_const_stable(feature = "const_ptr_is_null", since = "1.84.0")]
|
||||
#[inline]
|
||||
|
|
@ -332,28 +297,15 @@ impl<T: PointeeSized> *mut T {
|
|||
unsafe { &*self }
|
||||
}
|
||||
|
||||
/// Returns `None` if the pointer is null, or else returns a shared reference to
|
||||
/// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require
|
||||
/// that the value has to be initialized.
|
||||
///
|
||||
/// For the mutable counterpart see [`as_uninit_mut`].
|
||||
///
|
||||
/// [`as_ref`]: pointer#method.as_ref-1
|
||||
/// [`as_uninit_mut`]: #method.as_uninit_mut
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// When calling this method, you have to ensure that *either* the pointer is null *or*
|
||||
/// the pointer is [convertible to a reference](crate::ptr#pointer-to-reference-conversion).
|
||||
/// Note that because the created reference is to `MaybeUninit<T>`, the
|
||||
/// source pointer can point to uninitialized memory.
|
||||
///
|
||||
/// # Panics during const evaluation
|
||||
///
|
||||
/// This method will panic during const evaluation if the pointer cannot be
|
||||
/// determined to be null or not. See [`is_null`] for more information.
|
||||
#[doc = include_str!("./docs/as_uninit_ref.md")]
|
||||
///
|
||||
/// [`is_null`]: #method.is_null-1
|
||||
/// [`as_ref`]: pointer#method.as_ref-1
|
||||
///
|
||||
/// # See Also
|
||||
/// For the mutable counterpart see [`as_uninit_mut`].
|
||||
///
|
||||
/// [`as_uninit_mut`]: #method.as_uninit_mut
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
|||
|
|
@ -717,3 +717,10 @@ fn array_map_drops_unmapped_elements_on_panic() {
|
|||
assert_eq!(counter.load(Ordering::SeqCst), MAX);
|
||||
}
|
||||
}
|
||||
|
||||
// This covers the `PartialEq::<[T]>::eq` impl for `[T; N]` when it returns false.
|
||||
#[test]
|
||||
fn array_eq() {
|
||||
let not_true = [0u8] == [].as_slice();
|
||||
assert!(!not_true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,12 +17,6 @@ const TOL: f128 = 1e-12;
|
|||
#[allow(unused)]
|
||||
const TOL_PRECISE: f128 = 1e-28;
|
||||
|
||||
/// First pattern over the mantissa
|
||||
const NAN_MASK1: u128 = 0x0000aaaaaaaaaaaaaaaaaaaaaaaaaaaa;
|
||||
|
||||
/// Second pattern over the mantissa
|
||||
const NAN_MASK2: u128 = 0x00005555555555555555555555555555;
|
||||
|
||||
// FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support
|
||||
// the intrinsics.
|
||||
|
||||
|
|
@ -54,28 +48,6 @@ fn test_max_recip() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_float_bits_conv() {
|
||||
assert_eq!((1f128).to_bits(), 0x3fff0000000000000000000000000000);
|
||||
assert_eq!((12.5f128).to_bits(), 0x40029000000000000000000000000000);
|
||||
assert_eq!((1337f128).to_bits(), 0x40094e40000000000000000000000000);
|
||||
assert_eq!((-14.25f128).to_bits(), 0xc002c800000000000000000000000000);
|
||||
assert_biteq!(f128::from_bits(0x3fff0000000000000000000000000000), 1.0);
|
||||
assert_biteq!(f128::from_bits(0x40029000000000000000000000000000), 12.5);
|
||||
assert_biteq!(f128::from_bits(0x40094e40000000000000000000000000), 1337.0);
|
||||
assert_biteq!(f128::from_bits(0xc002c800000000000000000000000000), -14.25);
|
||||
|
||||
// Check that NaNs roundtrip their bits regardless of signaling-ness
|
||||
// 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
|
||||
let masked_nan1 = f128::NAN.to_bits() ^ NAN_MASK1;
|
||||
let masked_nan2 = f128::NAN.to_bits() ^ NAN_MASK2;
|
||||
assert!(f128::from_bits(masked_nan1).is_nan());
|
||||
assert!(f128::from_bits(masked_nan2).is_nan());
|
||||
|
||||
assert_eq!(f128::from_bits(masked_nan1).to_bits(), masked_nan1);
|
||||
assert_eq!(f128::from_bits(masked_nan2).to_bits(), masked_nan2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from() {
|
||||
assert_biteq!(f128::from(false), 0.0);
|
||||
|
|
|
|||
|
|
@ -19,12 +19,6 @@ const TOL_P2: f16 = 0.5;
|
|||
#[allow(unused)]
|
||||
const TOL_P4: f16 = 10.0;
|
||||
|
||||
/// First pattern over the mantissa
|
||||
const NAN_MASK1: u16 = 0x02aa;
|
||||
|
||||
/// Second pattern over the mantissa
|
||||
const NAN_MASK2: u16 = 0x0155;
|
||||
|
||||
// FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support
|
||||
// the intrinsics.
|
||||
|
||||
|
|
@ -52,27 +46,6 @@ fn test_max_recip() {
|
|||
assert_approx_eq!(f16::MAX.recip(), 1.526624e-5f16, 1e-4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_float_bits_conv() {
|
||||
assert_eq!((1f16).to_bits(), 0x3c00);
|
||||
assert_eq!((12.5f16).to_bits(), 0x4a40);
|
||||
assert_eq!((1337f16).to_bits(), 0x6539);
|
||||
assert_eq!((-14.25f16).to_bits(), 0xcb20);
|
||||
assert_biteq!(f16::from_bits(0x3c00), 1.0);
|
||||
assert_biteq!(f16::from_bits(0x4a40), 12.5);
|
||||
assert_biteq!(f16::from_bits(0x6539), 1337.0);
|
||||
assert_biteq!(f16::from_bits(0xcb20), -14.25);
|
||||
|
||||
// Check that NaNs roundtrip their bits regardless of signaling-ness
|
||||
let masked_nan1 = f16::NAN.to_bits() ^ NAN_MASK1;
|
||||
let masked_nan2 = f16::NAN.to_bits() ^ NAN_MASK2;
|
||||
assert!(f16::from_bits(masked_nan1).is_nan());
|
||||
assert!(f16::from_bits(masked_nan2).is_nan());
|
||||
|
||||
assert_eq!(f16::from_bits(masked_nan1).to_bits(), masked_nan1);
|
||||
assert_eq!(f16::from_bits(masked_nan2).to_bits(), masked_nan2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from() {
|
||||
assert_biteq!(f16::from(false), 0.0);
|
||||
|
|
|
|||
|
|
@ -2,12 +2,6 @@ use core::f32;
|
|||
|
||||
use super::assert_biteq;
|
||||
|
||||
/// First pattern over the mantissa
|
||||
const NAN_MASK1: u32 = 0x002a_aaaa;
|
||||
|
||||
/// Second pattern over the mantissa
|
||||
const NAN_MASK2: u32 = 0x0055_5555;
|
||||
|
||||
// FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/
|
||||
#[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)]
|
||||
#[test]
|
||||
|
|
@ -25,25 +19,3 @@ fn test_mul_add() {
|
|||
assert_biteq!(f32::math::mul_add(8.9f32, inf, 3.2), inf);
|
||||
assert_biteq!(f32::math::mul_add(-3.2f32, 2.4, neg_inf), neg_inf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_float_bits_conv() {
|
||||
assert_eq!((1f32).to_bits(), 0x3f800000);
|
||||
assert_eq!((12.5f32).to_bits(), 0x41480000);
|
||||
assert_eq!((1337f32).to_bits(), 0x44a72000);
|
||||
assert_eq!((-14.25f32).to_bits(), 0xc1640000);
|
||||
assert_biteq!(f32::from_bits(0x3f800000), 1.0);
|
||||
assert_biteq!(f32::from_bits(0x41480000), 12.5);
|
||||
assert_biteq!(f32::from_bits(0x44a72000), 1337.0);
|
||||
assert_biteq!(f32::from_bits(0xc1640000), -14.25);
|
||||
|
||||
// Check that NaNs roundtrip their bits regardless of signaling-ness
|
||||
// 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
|
||||
let masked_nan1 = f32::NAN.to_bits() ^ NAN_MASK1;
|
||||
let masked_nan2 = f32::NAN.to_bits() ^ NAN_MASK2;
|
||||
assert!(f32::from_bits(masked_nan1).is_nan());
|
||||
assert!(f32::from_bits(masked_nan2).is_nan());
|
||||
|
||||
assert_eq!(f32::from_bits(masked_nan1).to_bits(), masked_nan1);
|
||||
assert_eq!(f32::from_bits(masked_nan2).to_bits(), masked_nan2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,6 @@ use core::f64;
|
|||
|
||||
use super::assert_biteq;
|
||||
|
||||
/// First pattern over the mantissa
|
||||
const NAN_MASK1: u64 = 0x000a_aaaa_aaaa_aaaa;
|
||||
|
||||
/// Second pattern over the mantissa
|
||||
const NAN_MASK2: u64 = 0x0005_5555_5555_5555;
|
||||
|
||||
// FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/
|
||||
#[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)]
|
||||
#[test]
|
||||
|
|
@ -25,24 +19,3 @@ fn test_mul_add() {
|
|||
assert_biteq!(8.9f64.mul_add(inf, 3.2), inf);
|
||||
assert_biteq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_float_bits_conv() {
|
||||
assert_eq!((1f64).to_bits(), 0x3ff0000000000000);
|
||||
assert_eq!((12.5f64).to_bits(), 0x4029000000000000);
|
||||
assert_eq!((1337f64).to_bits(), 0x4094e40000000000);
|
||||
assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000);
|
||||
assert_biteq!(f64::from_bits(0x3ff0000000000000), 1.0);
|
||||
assert_biteq!(f64::from_bits(0x4029000000000000), 12.5);
|
||||
assert_biteq!(f64::from_bits(0x4094e40000000000), 1337.0);
|
||||
assert_biteq!(f64::from_bits(0xc02c800000000000), -14.25);
|
||||
|
||||
// Check that NaNs roundtrip their bits regardless of signaling-ness
|
||||
let masked_nan1 = f64::NAN.to_bits() ^ NAN_MASK1;
|
||||
let masked_nan2 = f64::NAN.to_bits() ^ NAN_MASK2;
|
||||
assert!(f64::from_bits(masked_nan1).is_nan());
|
||||
assert!(f64::from_bits(masked_nan2).is_nan());
|
||||
|
||||
assert_eq!(f64::from_bits(masked_nan1).to_bits(), masked_nan1);
|
||||
assert_eq!(f64::from_bits(masked_nan2).to_bits(), masked_nan2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@ trait TestableFloat: Sized {
|
|||
const EPS_ADD: Self;
|
||||
const EPS_MUL: Self;
|
||||
const EPS_DIV: Self;
|
||||
const RAW_1: Self;
|
||||
const RAW_12_DOT_5: Self;
|
||||
const RAW_1337: Self;
|
||||
const RAW_MINUS_14_DOT_25: Self;
|
||||
}
|
||||
|
||||
impl TestableFloat for f16 {
|
||||
|
|
@ -50,6 +54,10 @@ impl TestableFloat for f16 {
|
|||
const EPS_ADD: Self = if cfg!(miri) { 1e1 } else { 0.0 };
|
||||
const EPS_MUL: Self = if cfg!(miri) { 1e3 } else { 0.0 };
|
||||
const EPS_DIV: Self = if cfg!(miri) { 1e0 } else { 0.0 };
|
||||
const RAW_1: Self = Self::from_bits(0x3c00);
|
||||
const RAW_12_DOT_5: Self = Self::from_bits(0x4a40);
|
||||
const RAW_1337: Self = Self::from_bits(0x6539);
|
||||
const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xcb20);
|
||||
}
|
||||
|
||||
impl TestableFloat for f32 {
|
||||
|
|
@ -72,6 +80,10 @@ impl TestableFloat for f32 {
|
|||
const EPS_ADD: Self = if cfg!(miri) { 1e-3 } else { 0.0 };
|
||||
const EPS_MUL: Self = if cfg!(miri) { 1e-1 } else { 0.0 };
|
||||
const EPS_DIV: Self = if cfg!(miri) { 1e-4 } else { 0.0 };
|
||||
const RAW_1: Self = Self::from_bits(0x3f800000);
|
||||
const RAW_12_DOT_5: Self = Self::from_bits(0x41480000);
|
||||
const RAW_1337: Self = Self::from_bits(0x44a72000);
|
||||
const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xc1640000);
|
||||
}
|
||||
|
||||
impl TestableFloat for f64 {
|
||||
|
|
@ -90,6 +102,10 @@ impl TestableFloat for f64 {
|
|||
const EPS_ADD: Self = if cfg!(miri) { 1e-6 } else { 0.0 };
|
||||
const EPS_MUL: Self = if cfg!(miri) { 1e-6 } else { 0.0 };
|
||||
const EPS_DIV: Self = if cfg!(miri) { 1e-6 } else { 0.0 };
|
||||
const RAW_1: Self = Self::from_bits(0x3ff0000000000000);
|
||||
const RAW_12_DOT_5: Self = Self::from_bits(0x4029000000000000);
|
||||
const RAW_1337: Self = Self::from_bits(0x4094e40000000000);
|
||||
const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xc02c800000000000);
|
||||
}
|
||||
|
||||
impl TestableFloat for f128 {
|
||||
|
|
@ -108,6 +124,10 @@ impl TestableFloat for f128 {
|
|||
const EPS_ADD: Self = if cfg!(miri) { 1e-6 } else { 0.0 };
|
||||
const EPS_MUL: Self = if cfg!(miri) { 1e-6 } else { 0.0 };
|
||||
const EPS_DIV: Self = if cfg!(miri) { 1e-6 } else { 0.0 };
|
||||
const RAW_1: Self = Self::from_bits(0x3fff0000000000000000000000000000);
|
||||
const RAW_12_DOT_5: Self = Self::from_bits(0x40029000000000000000000000000000);
|
||||
const RAW_1337: Self = Self::from_bits(0x40094e40000000000000000000000000);
|
||||
const RAW_MINUS_14_DOT_25: Self = Self::from_bits(0xc002c800000000000000000000000000);
|
||||
}
|
||||
|
||||
/// Determine the tolerance for values of the argument type.
|
||||
|
|
@ -250,6 +270,8 @@ macro_rules! float_test {
|
|||
$( $( #[$f16_meta] )+ )?
|
||||
fn test_f16() {
|
||||
type $fty = f16;
|
||||
#[allow(unused)]
|
||||
const fn flt (x: $fty) -> $fty { x }
|
||||
$test
|
||||
}
|
||||
|
||||
|
|
@ -257,6 +279,8 @@ macro_rules! float_test {
|
|||
$( $( #[$f32_meta] )+ )?
|
||||
fn test_f32() {
|
||||
type $fty = f32;
|
||||
#[allow(unused)]
|
||||
const fn flt (x: $fty) -> $fty { x }
|
||||
$test
|
||||
}
|
||||
|
||||
|
|
@ -264,6 +288,8 @@ macro_rules! float_test {
|
|||
$( $( #[$f64_meta] )+ )?
|
||||
fn test_f64() {
|
||||
type $fty = f64;
|
||||
#[allow(unused)]
|
||||
const fn flt (x: $fty) -> $fty { x }
|
||||
$test
|
||||
}
|
||||
|
||||
|
|
@ -271,6 +297,8 @@ macro_rules! float_test {
|
|||
$( $( #[$f128_meta] )+ )?
|
||||
fn test_f128() {
|
||||
type $fty = f128;
|
||||
#[allow(unused)]
|
||||
const fn flt (x: $fty) -> $fty { x }
|
||||
$test
|
||||
}
|
||||
|
||||
|
|
@ -293,6 +321,8 @@ macro_rules! float_test {
|
|||
$( $( #[$f16_const_meta] )+ )?
|
||||
fn test_f16() {
|
||||
type $fty = f16;
|
||||
#[allow(unused)]
|
||||
const fn flt (x: $fty) -> $fty { x }
|
||||
const { $test }
|
||||
}
|
||||
|
||||
|
|
@ -300,6 +330,8 @@ macro_rules! float_test {
|
|||
$( $( #[$f32_const_meta] )+ )?
|
||||
fn test_f32() {
|
||||
type $fty = f32;
|
||||
#[allow(unused)]
|
||||
const fn flt (x: $fty) -> $fty { x }
|
||||
const { $test }
|
||||
}
|
||||
|
||||
|
|
@ -307,6 +339,8 @@ macro_rules! float_test {
|
|||
$( $( #[$f64_const_meta] )+ )?
|
||||
fn test_f64() {
|
||||
type $fty = f64;
|
||||
#[allow(unused)]
|
||||
const fn flt (x: $fty) -> $fty { x }
|
||||
const { $test }
|
||||
}
|
||||
|
||||
|
|
@ -314,6 +348,8 @@ macro_rules! float_test {
|
|||
$( $( #[$f128_const_meta] )+ )?
|
||||
fn test_f128() {
|
||||
type $fty = f128;
|
||||
#[allow(unused)]
|
||||
const fn flt (x: $fty) -> $fty { x }
|
||||
const { $test }
|
||||
}
|
||||
}
|
||||
|
|
@ -1479,3 +1515,30 @@ float_test! {
|
|||
assert_approx_eq!(a.algebraic_rem(b), a % b, Float::EPS_DIV);
|
||||
}
|
||||
}
|
||||
|
||||
float_test! {
|
||||
name: to_bits_conv,
|
||||
attrs: {
|
||||
f16: #[cfg(target_has_reliable_f16)],
|
||||
f128: #[cfg(target_has_reliable_f128)],
|
||||
},
|
||||
test<Float> {
|
||||
assert_biteq!(flt(1.0), Float::RAW_1);
|
||||
assert_biteq!(flt(12.5), Float::RAW_12_DOT_5);
|
||||
assert_biteq!(flt(1337.0), Float::RAW_1337);
|
||||
assert_biteq!(flt(-14.25), Float::RAW_MINUS_14_DOT_25);
|
||||
assert_biteq!(Float::RAW_1, 1.0);
|
||||
assert_biteq!(Float::RAW_12_DOT_5, 12.5);
|
||||
assert_biteq!(Float::RAW_1337, 1337.0);
|
||||
assert_biteq!(Float::RAW_MINUS_14_DOT_25, -14.25);
|
||||
|
||||
// Check that NaNs roundtrip their bits regardless of signaling-ness
|
||||
let masked_nan1 = Float::NAN.to_bits() ^ Float::NAN_MASK1;
|
||||
let masked_nan2 = Float::NAN.to_bits() ^ Float::NAN_MASK2;
|
||||
assert!(Float::from_bits(masked_nan1).is_nan());
|
||||
assert!(Float::from_bits(masked_nan2).is_nan());
|
||||
|
||||
assert_biteq!(Float::from_bits(masked_nan1), Float::from_bits(masked_nan1));
|
||||
assert_biteq!(Float::from_bits(masked_nan2), Float::from_bits(masked_nan2));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
#![feature(next_index)]
|
||||
#![feature(non_exhaustive_omitted_patterns_lint)]
|
||||
#![feature(numfmt)]
|
||||
#![feature(one_sided_range)]
|
||||
#![feature(option_reduce)]
|
||||
#![feature(pattern)]
|
||||
#![feature(peekable_next_if_map)]
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ mod control_flow;
|
|||
mod from_residual;
|
||||
|
||||
use core::ops::{
|
||||
Bound, Deref, DerefMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
|
||||
Bound, Deref, DerefMut, OneSidedRange, OneSidedRangeBound, Range, RangeBounds, RangeFrom,
|
||||
RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
|
||||
};
|
||||
|
||||
// Test the Range structs and syntax.
|
||||
|
|
@ -70,6 +71,36 @@ fn test_range_to_inclusive() {
|
|||
let _ = RangeToInclusive { end: 42 };
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_contains() {
|
||||
assert!(!(1u32..5).contains(&0u32));
|
||||
assert!((1u32..5).contains(&1u32));
|
||||
assert!((1u32..5).contains(&4u32));
|
||||
assert!(!(1u32..5).contains(&5u32));
|
||||
assert!(!(1u32..5).contains(&6u32));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_to_contains() {
|
||||
assert!(!(1u32..=5).contains(&0));
|
||||
assert!((1u32..=5).contains(&1));
|
||||
assert!((1u32..=5).contains(&4));
|
||||
assert!((1u32..=5).contains(&5));
|
||||
assert!(!(1u32..=5).contains(&6));
|
||||
}
|
||||
|
||||
// This test covers `RangeBounds::contains` when the start is excluded,
|
||||
// which cannot be directly expressed by Rust's built-in range syntax.
|
||||
#[test]
|
||||
fn test_range_bounds_contains() {
|
||||
let r = (Bound::Excluded(1u32), Bound::Included(5u32));
|
||||
assert!(!r.contains(&0));
|
||||
assert!(!r.contains(&1));
|
||||
assert!(r.contains(&3));
|
||||
assert!(r.contains(&5));
|
||||
assert!(!r.contains(&6));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_is_empty() {
|
||||
assert!(!(0.0..10.0).is_empty());
|
||||
|
|
@ -91,6 +122,34 @@ fn test_range_is_empty() {
|
|||
assert!((f32::NAN..=f32::NAN).is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_inclusive_end_bound() {
|
||||
let mut r = 1u32..=1;
|
||||
r.next().unwrap();
|
||||
assert!(!r.contains(&1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_bounds() {
|
||||
let r = (Bound::Included(1u32), Bound::Excluded(5u32));
|
||||
assert!(!r.contains(&0));
|
||||
assert!(r.contains(&1));
|
||||
assert!(r.contains(&3));
|
||||
assert!(!r.contains(&5));
|
||||
assert!(!r.contains(&6));
|
||||
|
||||
let r = (Bound::<u32>::Unbounded, Bound::Unbounded);
|
||||
assert!(r.contains(&0));
|
||||
assert!(r.contains(&u32::MAX));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_one_sided_range_bound() {
|
||||
assert!(matches!((..1u32).bound(), (OneSidedRangeBound::End, 1)));
|
||||
assert!(matches!((1u32..).bound(), (OneSidedRangeBound::StartInclusive, 1)));
|
||||
assert!(matches!((..=1u32).bound(), (OneSidedRangeBound::EndInclusive, 1)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bound_cloned_unbounded() {
|
||||
assert_eq!(Bound::<&u32>::Unbounded.cloned(), Bound::Unbounded);
|
||||
|
|
@ -240,3 +299,17 @@ fn deref_on_ref() {
|
|||
fn test_not_never() {
|
||||
if !return () {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fmt() {
|
||||
let mut r = 1..=1;
|
||||
assert_eq!(format!("{:?}", r), "1..=1");
|
||||
r.next().unwrap();
|
||||
assert_eq!(format!("{:?}", r), "1..=1 (exhausted)");
|
||||
|
||||
assert_eq!(format!("{:?}", 1..1), "1..1");
|
||||
assert_eq!(format!("{:?}", 1..), "1..");
|
||||
assert_eq!(format!("{:?}", ..1), "..1");
|
||||
assert_eq!(format!("{:?}", ..=1), "..=1");
|
||||
assert_eq!(format!("{:?}", ..), "..");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ pub mod process;
|
|||
pub mod random;
|
||||
pub mod stdio;
|
||||
pub mod sync;
|
||||
pub mod thread;
|
||||
pub mod thread_local;
|
||||
|
||||
// FIXME(117276): remove this, move feature implementations into individual
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ pub mod futex;
|
|||
pub mod os;
|
||||
#[path = "../unsupported/pipe.rs"]
|
||||
pub mod pipe;
|
||||
pub mod thread;
|
||||
pub mod time;
|
||||
|
||||
pub fn unsupported<T>() -> crate::io::Result<T> {
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64
|
|||
let tls_guard = unsafe { tls.activate() };
|
||||
|
||||
if secondary {
|
||||
let join_notifier = super::thread::Thread::entry();
|
||||
let join_notifier = crate::sys::thread::Thread::entry();
|
||||
drop(tls_guard);
|
||||
drop(join_notifier);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ mod libunwind_integration;
|
|||
pub mod os;
|
||||
#[path = "../unsupported/pipe.rs"]
|
||||
pub mod pipe;
|
||||
pub mod thread;
|
||||
pub mod thread_parking;
|
||||
pub mod time;
|
||||
pub mod waitqueue;
|
||||
|
|
|
|||
|
|
@ -10,10 +10,8 @@ pub mod itron {
|
|||
pub mod error;
|
||||
pub mod spin;
|
||||
pub mod task;
|
||||
pub mod thread;
|
||||
pub mod thread_parking;
|
||||
pub mod time;
|
||||
use super::unsupported;
|
||||
}
|
||||
|
||||
// `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as
|
||||
|
|
@ -22,7 +20,7 @@ pub(crate) mod error;
|
|||
pub mod os;
|
||||
#[path = "../unsupported/pipe.rs"]
|
||||
pub mod pipe;
|
||||
pub use self::itron::{thread, thread_parking};
|
||||
pub use self::itron::thread_parking;
|
||||
pub mod time;
|
||||
|
||||
// SAFETY: must be called only once during runtime initialization.
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
pub mod os;
|
||||
#[path = "../unsupported/pipe.rs"]
|
||||
pub mod pipe;
|
||||
pub mod thread;
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[path = "../unix/time.rs"]
|
||||
pub mod time;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ pub mod helpers;
|
|||
pub mod os;
|
||||
#[path = "../unsupported/pipe.rs"]
|
||||
pub mod pipe;
|
||||
pub mod thread;
|
||||
pub mod time;
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
|
|
@ -1,66 +0,0 @@
|
|||
use super::unsupported;
|
||||
use crate::ffi::CStr;
|
||||
use crate::io;
|
||||
use crate::num::NonZero;
|
||||
use crate::ptr::NonNull;
|
||||
use crate::time::{Duration, Instant};
|
||||
|
||||
pub struct Thread(!);
|
||||
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024;
|
||||
|
||||
impl Thread {
|
||||
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
|
||||
pub unsafe fn new(
|
||||
_stack: usize,
|
||||
_name: Option<&str>,
|
||||
_p: Box<dyn FnOnce()>,
|
||||
) -> io::Result<Thread> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
pub fn set_name(_name: &CStr) {
|
||||
// nope
|
||||
}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
let boot_services: NonNull<r_efi::efi::BootServices> =
|
||||
crate::os::uefi::env::boot_services().expect("can't sleep").cast();
|
||||
let mut dur_ms = dur.as_micros();
|
||||
// ceil up to the nearest microsecond
|
||||
if dur.subsec_nanos() % 1000 > 0 {
|
||||
dur_ms += 1;
|
||||
}
|
||||
|
||||
while dur_ms > 0 {
|
||||
let ms = crate::cmp::min(dur_ms, usize::MAX as u128);
|
||||
let _ = unsafe { ((*boot_services.as_ptr()).stall)(ms as usize) };
|
||||
dur_ms -= ms;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sleep_until(deadline: Instant) {
|
||||
let now = Instant::now();
|
||||
|
||||
if let Some(delay) = deadline.checked_duration_since(now) {
|
||||
Self::sleep(delay);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join(self) {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn current_os_id() -> Option<u64> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
|
||||
// UEFI is single threaded
|
||||
Ok(NonZero::new(1).unwrap())
|
||||
}
|
||||
|
|
@ -17,7 +17,6 @@ pub mod os;
|
|||
pub mod pipe;
|
||||
pub mod stack_overflow;
|
||||
pub mod sync;
|
||||
pub mod thread;
|
||||
pub mod thread_parking;
|
||||
pub mod time;
|
||||
|
||||
|
|
@ -55,7 +54,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
|
|||
// thread-id for the main thread and so renaming the main thread will rename the
|
||||
// process and we only want to enable this on platforms we've tested.
|
||||
if cfg!(target_vendor = "apple") {
|
||||
thread::Thread::set_name(&c"main");
|
||||
crate::sys::thread::set_name(c"main");
|
||||
}
|
||||
|
||||
unsafe fn sanitize_standard_fds() {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ pub mod futex;
|
|||
pub mod os;
|
||||
#[path = "../unsupported/pipe.rs"]
|
||||
pub mod pipe;
|
||||
pub mod thread;
|
||||
pub mod time;
|
||||
|
||||
#[path = "../unsupported/common.rs"]
|
||||
|
|
|
|||
|
|
@ -1,214 +0,0 @@
|
|||
#![forbid(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
use crate::ffi::CStr;
|
||||
use crate::num::NonZero;
|
||||
use crate::time::{Duration, Instant};
|
||||
use crate::{io, mem};
|
||||
|
||||
cfg_select! {
|
||||
target_feature = "atomics" => {
|
||||
use crate::cmp;
|
||||
use crate::ptr;
|
||||
use crate::sys::os;
|
||||
// Add a few symbols not in upstream `libc` just yet.
|
||||
mod libc {
|
||||
pub use crate::ffi;
|
||||
pub use libc::*;
|
||||
|
||||
// defined in wasi-libc
|
||||
// https://github.com/WebAssembly/wasi-libc/blob/a6f871343313220b76009827ed0153586361c0d5/libc-top-half/musl/include/alltypes.h.in#L108
|
||||
#[repr(C)]
|
||||
union pthread_attr_union {
|
||||
__i: [ffi::c_int; if size_of::<ffi::c_long>() == 8 { 14 } else { 9 }],
|
||||
__vi: [ffi::c_int; if size_of::<ffi::c_long>() == 8 { 14 } else { 9 }],
|
||||
__s: [ffi::c_ulong; if size_of::<ffi::c_long>() == 8 { 7 } else { 9 }],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct pthread_attr_t {
|
||||
__u: pthread_attr_union,
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type pthread_t = *mut ffi::c_void;
|
||||
|
||||
pub const _SC_NPROCESSORS_ONLN: ffi::c_int = 84;
|
||||
|
||||
unsafe extern "C" {
|
||||
pub fn pthread_create(
|
||||
native: *mut pthread_t,
|
||||
attr: *const pthread_attr_t,
|
||||
f: extern "C" fn(*mut ffi::c_void) -> *mut ffi::c_void,
|
||||
value: *mut ffi::c_void,
|
||||
) -> ffi::c_int;
|
||||
pub fn pthread_join(native: pthread_t, value: *mut *mut ffi::c_void) -> ffi::c_int;
|
||||
pub fn pthread_attr_init(attrp: *mut pthread_attr_t) -> ffi::c_int;
|
||||
pub fn pthread_attr_setstacksize(
|
||||
attr: *mut pthread_attr_t,
|
||||
stack_size: libc::size_t,
|
||||
) -> ffi::c_int;
|
||||
pub fn pthread_attr_destroy(attr: *mut pthread_attr_t) -> ffi::c_int;
|
||||
pub fn pthread_detach(thread: pthread_t) -> ffi::c_int;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Thread {
|
||||
id: libc::pthread_t,
|
||||
}
|
||||
|
||||
impl Drop for Thread {
|
||||
fn drop(&mut self) {
|
||||
let ret = unsafe { libc::pthread_detach(self.id) };
|
||||
debug_assert_eq!(ret, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
pub struct Thread(!);
|
||||
}
|
||||
}
|
||||
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
|
||||
|
||||
impl Thread {
|
||||
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
|
||||
cfg_select! {
|
||||
target_feature = "atomics" => {
|
||||
pub unsafe fn new(stack: usize, _name: Option<&str>, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
||||
let p = Box::into_raw(Box::new(p));
|
||||
let mut native: libc::pthread_t = unsafe { mem::zeroed() };
|
||||
let mut attr: libc::pthread_attr_t = unsafe { mem::zeroed() };
|
||||
assert_eq!(unsafe { libc::pthread_attr_init(&mut attr) }, 0);
|
||||
|
||||
let stack_size = cmp::max(stack, DEFAULT_MIN_STACK_SIZE);
|
||||
|
||||
match unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) } {
|
||||
0 => {}
|
||||
n => {
|
||||
assert_eq!(n, libc::EINVAL);
|
||||
// EINVAL means |stack_size| is either too small or not a
|
||||
// multiple of the system page size. Because it's definitely
|
||||
// >= PTHREAD_STACK_MIN, it must be an alignment issue.
|
||||
// Round up to the nearest page and try again.
|
||||
let page_size = os::page_size();
|
||||
let stack_size =
|
||||
(stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1);
|
||||
assert_eq!(unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) }, 0);
|
||||
}
|
||||
};
|
||||
|
||||
let ret = unsafe { libc::pthread_create(&mut native, &attr, thread_start, p as *mut _) };
|
||||
// Note: if the thread creation fails and this assert fails, then p will
|
||||
// be leaked. However, an alternative design could cause double-free
|
||||
// which is clearly worse.
|
||||
assert_eq!(unsafe {libc::pthread_attr_destroy(&mut attr) }, 0);
|
||||
|
||||
return if ret != 0 {
|
||||
// The thread failed to start and as a result p was not consumed. Therefore, it is
|
||||
// safe to reconstruct the box so that it gets deallocated.
|
||||
unsafe { drop(Box::from_raw(p)); }
|
||||
Err(io::Error::from_raw_os_error(ret))
|
||||
} else {
|
||||
Ok(Thread { id: native })
|
||||
};
|
||||
|
||||
extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
|
||||
unsafe {
|
||||
// Finally, let's run some code.
|
||||
Box::from_raw(main as *mut Box<dyn FnOnce()>)();
|
||||
}
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
pub unsafe fn new(_stack: usize, _name: Option<&str>, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
||||
crate::sys::unsupported()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
let ret = unsafe { wasi::sched_yield() };
|
||||
debug_assert_eq!(ret, Ok(()));
|
||||
}
|
||||
|
||||
pub fn set_name(_name: &CStr) {
|
||||
// nope
|
||||
}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
let mut nanos = dur.as_nanos();
|
||||
while nanos > 0 {
|
||||
const USERDATA: wasi::Userdata = 0x0123_45678;
|
||||
|
||||
let clock = wasi::SubscriptionClock {
|
||||
id: wasi::CLOCKID_MONOTONIC,
|
||||
timeout: u64::try_from(nanos).unwrap_or(u64::MAX),
|
||||
precision: 0,
|
||||
flags: 0,
|
||||
};
|
||||
nanos -= u128::from(clock.timeout);
|
||||
|
||||
let in_ = wasi::Subscription {
|
||||
userdata: USERDATA,
|
||||
u: wasi::SubscriptionU { tag: 0, u: wasi::SubscriptionUU { clock } },
|
||||
};
|
||||
unsafe {
|
||||
let mut event: wasi::Event = mem::zeroed();
|
||||
let res = wasi::poll_oneoff(&in_, &mut event, 1);
|
||||
match (res, event) {
|
||||
(
|
||||
Ok(1),
|
||||
wasi::Event {
|
||||
userdata: USERDATA,
|
||||
error: wasi::ERRNO_SUCCESS,
|
||||
type_: wasi::EVENTTYPE_CLOCK,
|
||||
..
|
||||
},
|
||||
) => {}
|
||||
_ => panic!("thread::sleep(): unexpected result of poll_oneoff"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sleep_until(deadline: Instant) {
|
||||
let now = Instant::now();
|
||||
|
||||
if let Some(delay) = deadline.checked_duration_since(now) {
|
||||
Self::sleep(delay);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join(self) {
|
||||
cfg_select! {
|
||||
target_feature = "atomics" => {
|
||||
let id = mem::ManuallyDrop::new(self).id;
|
||||
let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
if ret != 0 {
|
||||
rtabort!("failed to join thread: {}", io::Error::from_raw_os_error(ret));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn current_os_id() -> Option<u64> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
|
||||
cfg_select! {
|
||||
target_feature = "atomics" => {
|
||||
match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
|
||||
-1 => Err(io::Error::last_os_error()),
|
||||
cpus => NonZero::new(cpus as usize).ok_or(io::Error::UNKNOWN_THREAD_COUNT),
|
||||
}
|
||||
}
|
||||
_ => crate::sys::unsupported(),
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,6 @@ pub mod futex;
|
|||
pub mod os;
|
||||
#[path = "../unsupported/pipe.rs"]
|
||||
pub mod pipe;
|
||||
pub mod thread;
|
||||
pub mod time;
|
||||
|
||||
#[path = "../unsupported/common.rs"]
|
||||
|
|
|
|||
|
|
@ -1,73 +0,0 @@
|
|||
use crate::ffi::CStr;
|
||||
use crate::io;
|
||||
use crate::num::NonZero;
|
||||
use crate::time::{Duration, Instant};
|
||||
|
||||
pub struct Thread(!);
|
||||
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
|
||||
|
||||
impl Thread {
|
||||
pub unsafe fn new(
|
||||
_stack: usize,
|
||||
_name: Option<&str>,
|
||||
_p: Box<dyn FnOnce()>,
|
||||
) -> io::Result<Thread> {
|
||||
// Note that unlike WASIp1 even if the wasm `atomics` feature is enabled
|
||||
// there is no support for threads, not even experimentally, not even in
|
||||
// wasi-libc. Thus this is unconditionally unsupported.
|
||||
crate::sys::unsupported()
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
// no API for this in WASIp2, but there's also no threads, so that's
|
||||
// sort of expected.
|
||||
}
|
||||
|
||||
pub fn set_name(_name: &CStr) {
|
||||
// nope
|
||||
}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
// Sleep in increments of `u64::MAX` nanoseconds until the `dur` is
|
||||
// entirely drained.
|
||||
let mut remaining = dur.as_nanos();
|
||||
while remaining > 0 {
|
||||
let amt = u64::try_from(remaining).unwrap_or(u64::MAX);
|
||||
wasip2::clocks::monotonic_clock::subscribe_duration(amt).block();
|
||||
remaining -= u128::from(amt);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sleep_until(deadline: Instant) {
|
||||
match u64::try_from(deadline.into_inner().as_duration().as_nanos()) {
|
||||
// If the point in time we're sleeping to fits within a 64-bit
|
||||
// number of nanoseconds then directly use `subscribe_instant`.
|
||||
Ok(deadline) => {
|
||||
wasip2::clocks::monotonic_clock::subscribe_instant(deadline).block();
|
||||
}
|
||||
// ... otherwise we're sleeping for 500+ years relative to the
|
||||
// "start" of what the system is using as a clock so speed/accuracy
|
||||
// is not so much of a concern. Use `sleep` instead.
|
||||
Err(_) => {
|
||||
let now = Instant::now();
|
||||
|
||||
if let Some(delay) = deadline.checked_duration_since(now) {
|
||||
Self::sleep(delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join(self) {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn current_os_id() -> Option<u64> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
|
||||
crate::sys::unsupported()
|
||||
}
|
||||
|
|
@ -25,7 +25,7 @@ impl Instant {
|
|||
Some(Instant(self.0.checked_sub(*other)?))
|
||||
}
|
||||
|
||||
pub(super) fn as_duration(&self) -> &Duration {
|
||||
pub(crate) fn as_duration(&self) -> &Duration {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,75 +0,0 @@
|
|||
use crate::ffi::CStr;
|
||||
use crate::io;
|
||||
use crate::num::NonZero;
|
||||
use crate::sys::unsupported;
|
||||
use crate::time::{Duration, Instant};
|
||||
|
||||
pub struct Thread(!);
|
||||
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
|
||||
|
||||
impl Thread {
|
||||
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
|
||||
pub unsafe fn new(
|
||||
_stack: usize,
|
||||
_name: Option<&str>,
|
||||
_p: Box<dyn FnOnce()>,
|
||||
) -> io::Result<Thread> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn yield_now() {}
|
||||
|
||||
pub fn set_name(_name: &CStr) {}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use core::arch::wasm32 as wasm;
|
||||
#[cfg(target_arch = "wasm64")]
|
||||
use core::arch::wasm64 as wasm;
|
||||
|
||||
use crate::cmp;
|
||||
|
||||
// Use an atomic wait to block the current thread artificially with a
|
||||
// timeout listed. Note that we should never be notified (return value
|
||||
// of 0) or our comparison should never fail (return value of 1) so we
|
||||
// should always only resume execution through a timeout (return value
|
||||
// 2).
|
||||
let mut nanos = dur.as_nanos();
|
||||
while nanos > 0 {
|
||||
let amt = cmp::min(i64::MAX as u128, nanos);
|
||||
let mut x = 0;
|
||||
let val = unsafe { wasm::memory_atomic_wait32(&mut x, 0, amt as i64) };
|
||||
debug_assert_eq!(val, 2);
|
||||
nanos -= amt;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sleep_until(deadline: Instant) {
|
||||
let now = Instant::now();
|
||||
|
||||
if let Some(delay) = deadline.checked_duration_since(now) {
|
||||
Self::sleep(delay);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join(self) {}
|
||||
}
|
||||
|
||||
pub(crate) fn current_os_id() -> Option<u64> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub mod guard {
|
||||
pub type Guard = !;
|
||||
pub unsafe fn current() -> Option<Guard> {
|
||||
None
|
||||
}
|
||||
pub unsafe fn init() -> Option<Guard> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
@ -23,18 +23,9 @@ pub mod pipe;
|
|||
#[path = "../unsupported/time.rs"]
|
||||
pub mod time;
|
||||
|
||||
cfg_select! {
|
||||
target_feature = "atomics" => {
|
||||
#[path = "atomics/futex.rs"]
|
||||
pub mod futex;
|
||||
#[path = "atomics/thread.rs"]
|
||||
pub mod thread;
|
||||
}
|
||||
_ => {
|
||||
#[path = "../unsupported/thread.rs"]
|
||||
pub mod thread;
|
||||
}
|
||||
}
|
||||
#[cfg(target_feature = "atomics")]
|
||||
#[path = "atomics/futex.rs"]
|
||||
pub mod futex;
|
||||
|
||||
#[path = "../unsupported/common.rs"]
|
||||
#[deny(unsafe_op_in_unsafe_fn)]
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ pub mod futex;
|
|||
pub mod handle;
|
||||
pub mod os;
|
||||
pub mod pipe;
|
||||
pub mod thread;
|
||||
pub mod time;
|
||||
cfg_select! {
|
||||
not(target_vendor = "uwp") => {
|
||||
|
|
@ -48,9 +47,9 @@ pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {
|
|||
unsafe {
|
||||
stack_overflow::init();
|
||||
|
||||
// Normally, `thread::spawn` will call `Thread::set_name` but since this thread already
|
||||
// Normally, `thread::spawn` will call `set_name` but since this thread already
|
||||
// exists, we have to call it ourselves.
|
||||
thread::Thread::set_name_wide(wide_str!("main"));
|
||||
crate::sys::thread::set_name_wide(wide_str!("main"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ mod perf_counter {
|
|||
}
|
||||
|
||||
/// A timer you can wait on.
|
||||
pub(super) struct WaitableTimer {
|
||||
pub(crate) struct WaitableTimer {
|
||||
handle: c::HANDLE,
|
||||
}
|
||||
impl WaitableTimer {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ use crate::os::xous::ffi::exit;
|
|||
pub mod os;
|
||||
#[path = "../unsupported/pipe.rs"]
|
||||
pub mod pipe;
|
||||
pub mod thread;
|
||||
pub mod time;
|
||||
|
||||
#[path = "../unsupported/common.rs"]
|
||||
|
|
|
|||
|
|
@ -35,9 +35,9 @@ fn compare_against_sw_vers() {
|
|||
assert_eq!(__isOSVersionAtLeast(major, minor, subminor), 1);
|
||||
|
||||
// One lower is available
|
||||
assert_eq!(__isOSVersionAtLeast(major, minor, subminor.saturating_sub(1)), 1);
|
||||
assert_eq!(__isOSVersionAtLeast(major, minor.saturating_sub(1), subminor), 1);
|
||||
assert_eq!(__isOSVersionAtLeast(major.saturating_sub(1), minor, subminor), 1);
|
||||
assert_eq!(__isOSVersionAtLeast(major, minor, (subminor as u32).saturating_sub(1) as i32), 1);
|
||||
assert_eq!(__isOSVersionAtLeast(major, (minor as u32).saturating_sub(1) as i32, subminor), 1);
|
||||
assert_eq!(__isOSVersionAtLeast((major as u32).saturating_sub(1) as i32, minor, subminor), 1);
|
||||
|
||||
// One higher isn't available
|
||||
assert_eq!(__isOSVersionAtLeast(major, minor, subminor + 1), 0);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,5 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use super::hermit_abi;
|
||||
use crate::ffi::CStr;
|
||||
use crate::mem::ManuallyDrop;
|
||||
use crate::num::NonZero;
|
||||
use crate::time::{Duration, Instant};
|
||||
use crate::time::Duration;
|
||||
use crate::{io, ptr};
|
||||
|
||||
pub type Tid = hermit_abi::Tid;
|
||||
|
|
@ -68,57 +63,30 @@ impl Thread {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn yield_now() {
|
||||
unsafe {
|
||||
hermit_abi::yield_now();
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_name(_name: &CStr) {
|
||||
// nope
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn sleep(dur: Duration) {
|
||||
let micros = dur.as_micros() + if dur.subsec_nanos() % 1_000 > 0 { 1 } else { 0 };
|
||||
let micros = u64::try_from(micros).unwrap_or(u64::MAX);
|
||||
|
||||
unsafe {
|
||||
hermit_abi::usleep(micros);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sleep_until(deadline: Instant) {
|
||||
let now = Instant::now();
|
||||
|
||||
if let Some(delay) = deadline.checked_duration_since(now) {
|
||||
Self::sleep(delay);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join(self) {
|
||||
unsafe {
|
||||
let _ = hermit_abi::join(self.tid);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn id(&self) -> Tid {
|
||||
self.tid
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn into_id(self) -> Tid {
|
||||
ManuallyDrop::new(self).tid
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn current_os_id() -> Option<u64> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
|
||||
unsafe { Ok(NonZero::new_unchecked(hermit_abi::available_parallelism())) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn sleep(dur: Duration) {
|
||||
let micros = dur.as_micros() + if dur.subsec_nanos() % 1_000 > 0 { 1 } else { 0 };
|
||||
let micros = u64::try_from(micros).unwrap_or(u64::MAX);
|
||||
|
||||
unsafe {
|
||||
hermit_abi::usleep(micros);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn yield_now() {
|
||||
unsafe {
|
||||
hermit_abi::yield_now();
|
||||
}
|
||||
}
|
||||
152
library/std/src/sys/thread/mod.rs
Normal file
152
library/std/src/sys/thread/mod.rs
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
cfg_select! {
|
||||
target_os = "hermit" => {
|
||||
mod hermit;
|
||||
pub use hermit::{Thread, available_parallelism, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
|
||||
#[expect(dead_code)]
|
||||
mod unsupported;
|
||||
pub use unsupported::{current_os_id, set_name};
|
||||
}
|
||||
all(target_vendor = "fortanix", target_env = "sgx") => {
|
||||
mod sgx;
|
||||
pub use sgx::{Thread, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
|
||||
|
||||
// SGX should protect in-enclave data from outside attackers, so there
|
||||
// must not be any data leakage to the OS, particularly no 1-1 mapping
|
||||
// between SGX thread names and OS thread names. Hence `set_name` is
|
||||
// intentionally a no-op.
|
||||
//
|
||||
// Note that the internally visible SGX thread name is already provided
|
||||
// by the platform-agnostic Rust thread code. This can be observed in
|
||||
// the [`std::thread::tests::test_named_thread`] test, which succeeds
|
||||
// as-is with the SGX target.
|
||||
#[expect(dead_code)]
|
||||
mod unsupported;
|
||||
pub use unsupported::{available_parallelism, set_name};
|
||||
}
|
||||
target_os = "solid_asp3" => {
|
||||
mod solid;
|
||||
pub use solid::{Thread, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
|
||||
#[expect(dead_code)]
|
||||
mod unsupported;
|
||||
pub use unsupported::{available_parallelism, current_os_id, set_name};
|
||||
}
|
||||
target_os = "teeos" => {
|
||||
mod teeos;
|
||||
pub use teeos::{Thread, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
|
||||
#[expect(dead_code)]
|
||||
mod unsupported;
|
||||
pub use unsupported::{available_parallelism, current_os_id, set_name};
|
||||
}
|
||||
target_os = "uefi" => {
|
||||
mod uefi;
|
||||
pub use uefi::{available_parallelism, sleep};
|
||||
#[expect(dead_code)]
|
||||
mod unsupported;
|
||||
pub use unsupported::{Thread, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
|
||||
}
|
||||
target_family = "unix" => {
|
||||
mod unix;
|
||||
pub use unix::{Thread, available_parallelism, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
|
||||
#[cfg(not(any(
|
||||
target_env = "newlib",
|
||||
target_os = "l4re",
|
||||
target_os = "emscripten",
|
||||
target_os = "redox",
|
||||
target_os = "hurd",
|
||||
target_os = "aix",
|
||||
)))]
|
||||
pub use unix::set_name;
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "dragonfly",
|
||||
target_os = "hurd",
|
||||
target_os = "fuchsia",
|
||||
target_os = "vxworks",
|
||||
))]
|
||||
pub use unix::sleep_until;
|
||||
#[expect(dead_code)]
|
||||
mod unsupported;
|
||||
#[cfg(any(
|
||||
target_env = "newlib",
|
||||
target_os = "l4re",
|
||||
target_os = "emscripten",
|
||||
target_os = "redox",
|
||||
target_os = "hurd",
|
||||
target_os = "aix",
|
||||
))]
|
||||
pub use unsupported::set_name;
|
||||
}
|
||||
all(target_os = "wasi", target_env = "p1") => {
|
||||
mod wasip1;
|
||||
pub use wasip1::{DEFAULT_MIN_STACK_SIZE, sleep, yield_now};
|
||||
#[cfg(target_feature = "atomics")]
|
||||
pub use wasip1::{Thread, available_parallelism};
|
||||
#[expect(dead_code)]
|
||||
mod unsupported;
|
||||
pub use unsupported::{current_os_id, set_name};
|
||||
#[cfg(not(target_feature = "atomics"))]
|
||||
pub use unsupported::{Thread, available_parallelism};
|
||||
}
|
||||
all(target_os = "wasi", target_env = "p2") => {
|
||||
mod wasip2;
|
||||
pub use wasip2::{sleep, sleep_until};
|
||||
#[expect(dead_code)]
|
||||
mod unsupported;
|
||||
// Note that unlike WASIp1 even if the wasm `atomics` feature is enabled
|
||||
// there is no support for threads, not even experimentally, not even in
|
||||
// wasi-libc. Thus this is unconditionally unsupported.
|
||||
pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
|
||||
}
|
||||
all(target_family = "wasm", target_feature = "atomics") => {
|
||||
mod wasm;
|
||||
pub use wasm::sleep;
|
||||
|
||||
#[expect(dead_code)]
|
||||
mod unsupported;
|
||||
pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
|
||||
}
|
||||
target_os = "windows" => {
|
||||
mod windows;
|
||||
pub use windows::{Thread, available_parallelism, current_os_id, set_name, set_name_wide, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
|
||||
}
|
||||
target_os = "xous" => {
|
||||
mod xous;
|
||||
pub use xous::{Thread, available_parallelism, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
|
||||
|
||||
#[expect(dead_code)]
|
||||
mod unsupported;
|
||||
pub use unsupported::{current_os_id, set_name};
|
||||
}
|
||||
_ => {
|
||||
mod unsupported;
|
||||
pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "dragonfly",
|
||||
target_os = "hurd",
|
||||
target_os = "fuchsia",
|
||||
target_os = "vxworks",
|
||||
all(target_os = "wasi", target_env = "p2"),
|
||||
)))]
|
||||
pub fn sleep_until(deadline: crate::time::Instant) {
|
||||
use crate::time::Instant;
|
||||
|
||||
let now = Instant::now();
|
||||
|
||||
if let Some(delay) = deadline.checked_duration_since(now) {
|
||||
sleep(delay);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,8 @@
|
|||
#![cfg_attr(test, allow(dead_code))] // why is this necessary?
|
||||
|
||||
use super::abi::{thread, usercalls};
|
||||
use super::unsupported;
|
||||
use crate::ffi::CStr;
|
||||
use crate::io;
|
||||
use crate::num::NonZero;
|
||||
use crate::time::{Duration, Instant};
|
||||
use crate::sys::pal::abi::{thread, usercalls};
|
||||
use crate::time::Duration;
|
||||
|
||||
pub struct Thread(task_queue::JoinHandle);
|
||||
|
||||
|
|
@ -108,51 +105,27 @@ impl Thread {
|
|||
Ok(Thread(handle))
|
||||
}
|
||||
|
||||
pub(super) fn entry() -> JoinNotifier {
|
||||
pub(crate) fn entry() -> JoinNotifier {
|
||||
let mut pending_tasks = task_queue::lock();
|
||||
let task = rtunwrap!(Some, pending_tasks.pop());
|
||||
drop(pending_tasks); // make sure to not hold the task queue lock longer than necessary
|
||||
task.run()
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
let wait_error = rtunwrap!(Err, usercalls::wait(0, usercalls::raw::WAIT_NO));
|
||||
rtassert!(wait_error.kind() == io::ErrorKind::WouldBlock);
|
||||
}
|
||||
|
||||
/// SGX should protect in-enclave data from the outside (attacker),
|
||||
/// so there should be no data leakage to the OS,
|
||||
/// and therefore also no 1-1 mapping between SGX thread names and OS thread names.
|
||||
///
|
||||
/// This is why the method is intentionally No-Op.
|
||||
pub fn set_name(_name: &CStr) {
|
||||
// Note that the internally visible SGX thread name is already provided
|
||||
// by the platform-agnostic (target-agnostic) Rust thread code.
|
||||
// This can be observed in the [`std::thread::tests::test_named_thread`] test,
|
||||
// which succeeds as-is with the SGX target.
|
||||
}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
usercalls::wait_timeout(0, dur, || true);
|
||||
}
|
||||
|
||||
pub fn sleep_until(deadline: Instant) {
|
||||
let now = Instant::now();
|
||||
|
||||
if let Some(delay) = deadline.checked_duration_since(now) {
|
||||
Self::sleep(delay);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join(self) {
|
||||
self.0.wait();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn current_os_id() -> Option<u64> {
|
||||
pub fn current_os_id() -> Option<u64> {
|
||||
Some(thread::current().addr().get() as u64)
|
||||
}
|
||||
|
||||
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
|
||||
unsupported()
|
||||
pub fn sleep(dur: Duration) {
|
||||
usercalls::wait_timeout(0, dur, || true);
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
let wait_error = rtunwrap!(Err, usercalls::wait(0, usercalls::raw::WAIT_NO));
|
||||
rtassert!(wait_error.kind() == io::ErrorKind::WouldBlock);
|
||||
}
|
||||
|
|
@ -1,16 +1,14 @@
|
|||
//! Thread implementation backed by μITRON tasks. Assumes `acre_tsk` and
|
||||
//! `exd_tsk` are available.
|
||||
|
||||
use super::error::{ItronError, expect_success, expect_success_aborting};
|
||||
use super::time::dur2reltims;
|
||||
use super::{abi, task};
|
||||
use crate::cell::UnsafeCell;
|
||||
use crate::ffi::CStr;
|
||||
use crate::mem::ManuallyDrop;
|
||||
use crate::num::NonZero;
|
||||
use crate::ptr::NonNull;
|
||||
use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
|
||||
use crate::time::{Duration, Instant};
|
||||
use crate::sys::pal::itron::error::{ItronError, expect_success, expect_success_aborting};
|
||||
use crate::sys::pal::itron::time::dur2reltims;
|
||||
use crate::sys::pal::itron::{abi, task};
|
||||
use crate::time::Duration;
|
||||
use crate::{hint, io};
|
||||
|
||||
pub struct Thread {
|
||||
|
|
@ -195,28 +193,6 @@ impl Thread {
|
|||
Ok(Self { p_inner, task: new_task })
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
expect_success(unsafe { abi::rot_rdq(abi::TPRI_SELF) }, &"rot_rdq");
|
||||
}
|
||||
|
||||
pub fn set_name(_name: &CStr) {
|
||||
// nope
|
||||
}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
for timeout in dur2reltims(dur) {
|
||||
expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sleep_until(deadline: Instant) {
|
||||
let now = Instant::now();
|
||||
|
||||
if let Some(delay) = deadline.checked_duration_since(now) {
|
||||
Self::sleep(delay);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join(self) {
|
||||
// Safety: `ThreadInner` is alive at this point
|
||||
let inner = unsafe { self.p_inner.as_ref() };
|
||||
|
|
@ -361,10 +337,12 @@ unsafe fn terminate_and_delete_current_task() -> ! {
|
|||
unsafe { crate::hint::unreachable_unchecked() };
|
||||
}
|
||||
|
||||
pub(crate) fn current_os_id() -> Option<u64> {
|
||||
None
|
||||
pub fn yield_now() {
|
||||
expect_success(unsafe { abi::rot_rdq(abi::TPRI_SELF) }, &"rot_rdq");
|
||||
}
|
||||
|
||||
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
|
||||
super::unsupported()
|
||||
pub fn sleep(dur: Duration) {
|
||||
for timeout in dur2reltims(dur) {
|
||||
expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,18 @@
|
|||
use crate::ffi::CStr;
|
||||
use crate::mem::{self, ManuallyDrop};
|
||||
use crate::num::NonZero;
|
||||
use crate::sys::os;
|
||||
use crate::time::{Duration, Instant};
|
||||
use crate::time::Duration;
|
||||
use crate::{cmp, io, ptr};
|
||||
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 8 * 1024;
|
||||
|
||||
unsafe extern "C" {
|
||||
safe fn TEE_Wait(timeout: u32) -> u32;
|
||||
}
|
||||
|
||||
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
|
||||
libc::PTHREAD_STACK_MIN.try_into().expect("Infallible")
|
||||
}
|
||||
|
||||
pub struct Thread {
|
||||
id: libc::pthread_t,
|
||||
}
|
||||
|
|
@ -16,10 +22,6 @@ pub struct Thread {
|
|||
unsafe impl Send for Thread {}
|
||||
unsafe impl Sync for Thread {}
|
||||
|
||||
unsafe extern "C" {
|
||||
pub fn TEE_Wait(timeout: u32) -> u32;
|
||||
}
|
||||
|
||||
impl Thread {
|
||||
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
|
||||
pub unsafe fn new(
|
||||
|
|
@ -74,7 +76,7 @@ impl Thread {
|
|||
} else {
|
||||
// The new thread will start running earliest after the next yield.
|
||||
// We add a yield here, so that the user does not have to.
|
||||
Thread::yield_now();
|
||||
yield_now();
|
||||
Ok(Thread { id: native })
|
||||
};
|
||||
|
||||
|
|
@ -91,36 +93,6 @@ impl Thread {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
let ret = unsafe { libc::sched_yield() };
|
||||
debug_assert_eq!(ret, 0);
|
||||
}
|
||||
|
||||
/// This does not do anything on teeos
|
||||
pub fn set_name(_name: &CStr) {
|
||||
// Both pthread_setname_np and prctl are not available to the TA,
|
||||
// so we can't implement this currently. If the need arises please
|
||||
// contact the teeos rustzone team.
|
||||
}
|
||||
|
||||
/// only main thread could wait for sometime in teeos
|
||||
pub fn sleep(dur: Duration) {
|
||||
let sleep_millis = dur.as_millis();
|
||||
let final_sleep: u32 =
|
||||
if sleep_millis >= u32::MAX as u128 { u32::MAX } else { sleep_millis as u32 };
|
||||
unsafe {
|
||||
let _ = TEE_Wait(final_sleep);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sleep_until(deadline: Instant) {
|
||||
let now = Instant::now();
|
||||
|
||||
if let Some(delay) = deadline.checked_duration_since(now) {
|
||||
Self::sleep(delay);
|
||||
}
|
||||
}
|
||||
|
||||
/// must join, because no pthread_detach supported
|
||||
pub fn join(self) {
|
||||
let id = self.into_id();
|
||||
|
|
@ -128,10 +100,6 @@ impl Thread {
|
|||
assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret));
|
||||
}
|
||||
|
||||
pub fn id(&self) -> libc::pthread_t {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub fn into_id(self) -> libc::pthread_t {
|
||||
ManuallyDrop::new(self).id
|
||||
}
|
||||
|
|
@ -144,16 +112,15 @@ impl Drop for Thread {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn current_os_id() -> Option<u64> {
|
||||
None
|
||||
pub fn yield_now() {
|
||||
let ret = unsafe { libc::sched_yield() };
|
||||
debug_assert_eq!(ret, 0);
|
||||
}
|
||||
|
||||
// Note: Both `sched_getaffinity` and `sysconf` are available but not functional on
|
||||
// teeos, so this function always returns an Error!
|
||||
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
|
||||
Err(io::Error::UNKNOWN_THREAD_COUNT)
|
||||
}
|
||||
|
||||
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
|
||||
libc::PTHREAD_STACK_MIN.try_into().expect("Infallible")
|
||||
/// only main thread could wait for sometime in teeos
|
||||
pub fn sleep(dur: Duration) {
|
||||
let sleep_millis = dur.as_millis();
|
||||
let final_sleep: u32 =
|
||||
if sleep_millis >= u32::MAX as u128 { u32::MAX } else { sleep_millis as u32 };
|
||||
TEE_Wait(final_sleep);
|
||||
}
|
||||
25
library/std/src/sys/thread/uefi.rs
Normal file
25
library/std/src/sys/thread/uefi.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
use crate::io;
|
||||
use crate::num::NonZero;
|
||||
use crate::ptr::NonNull;
|
||||
use crate::time::Duration;
|
||||
|
||||
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
|
||||
// UEFI is single threaded
|
||||
Ok(NonZero::new(1).unwrap())
|
||||
}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
let boot_services: NonNull<r_efi::efi::BootServices> =
|
||||
crate::os::uefi::env::boot_services().expect("can't sleep").cast();
|
||||
let mut dur_ms = dur.as_micros();
|
||||
// ceil up to the nearest microsecond
|
||||
if dur.subsec_nanos() % 1000 > 0 {
|
||||
dur_ms += 1;
|
||||
}
|
||||
|
||||
while dur_ms > 0 {
|
||||
let ms = crate::cmp::min(dur_ms, usize::MAX as u128);
|
||||
let _ = unsafe { ((*boot_services.as_ptr()).stall)(ms as usize) };
|
||||
dur_ms -= ms;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,11 @@
|
|||
#[cfg(not(any(
|
||||
target_env = "newlib",
|
||||
target_os = "l4re",
|
||||
target_os = "emscripten",
|
||||
target_os = "redox",
|
||||
target_os = "hurd",
|
||||
target_os = "aix",
|
||||
)))]
|
||||
use crate::ffi::CStr;
|
||||
use crate::mem::{self, ManuallyDrop};
|
||||
use crate::num::NonZero;
|
||||
|
|
@ -6,7 +14,7 @@ use crate::sys::weak::dlsym;
|
|||
#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto",))]
|
||||
use crate::sys::weak::weak;
|
||||
use crate::sys::{os, stack_overflow};
|
||||
use crate::time::{Duration, Instant};
|
||||
use crate::time::Duration;
|
||||
use crate::{cmp, io, ptr};
|
||||
#[cfg(not(any(
|
||||
target_os = "l4re",
|
||||
|
|
@ -121,273 +129,6 @@ impl Thread {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
let ret = unsafe { libc::sched_yield() };
|
||||
debug_assert_eq!(ret, 0);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
pub fn set_name(name: &CStr) {
|
||||
const PR_SET_NAME: libc::c_int = 15;
|
||||
unsafe {
|
||||
let res = libc::prctl(
|
||||
PR_SET_NAME,
|
||||
name.as_ptr(),
|
||||
0 as libc::c_ulong,
|
||||
0 as libc::c_ulong,
|
||||
0 as libc::c_ulong,
|
||||
);
|
||||
// We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
|
||||
debug_assert_eq!(res, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "nuttx",
|
||||
target_os = "cygwin"
|
||||
))]
|
||||
pub fn set_name(name: &CStr) {
|
||||
unsafe {
|
||||
cfg_select! {
|
||||
any(target_os = "linux", target_os = "cygwin") => {
|
||||
// Linux and Cygwin limits the allowed length of the name.
|
||||
const TASK_COMM_LEN: usize = 16;
|
||||
let name = truncate_cstr::<{ TASK_COMM_LEN }>(name);
|
||||
}
|
||||
_ => {
|
||||
// FreeBSD, DragonFly BSD and NuttX do not enforce length limits.
|
||||
}
|
||||
};
|
||||
// Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20 for Linux,
|
||||
// FreeBSD 12.2 and 13.0, and DragonFly BSD 6.0.
|
||||
let res = libc::pthread_setname_np(libc::pthread_self(), name.as_ptr());
|
||||
// We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
|
||||
debug_assert_eq!(res, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "openbsd")]
|
||||
pub fn set_name(name: &CStr) {
|
||||
unsafe {
|
||||
libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_vendor = "apple")]
|
||||
pub fn set_name(name: &CStr) {
|
||||
unsafe {
|
||||
let name = truncate_cstr::<{ libc::MAXTHREADNAMESIZE }>(name);
|
||||
let res = libc::pthread_setname_np(name.as_ptr());
|
||||
// We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
|
||||
debug_assert_eq!(res, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "netbsd")]
|
||||
pub fn set_name(name: &CStr) {
|
||||
unsafe {
|
||||
let res = libc::pthread_setname_np(
|
||||
libc::pthread_self(),
|
||||
c"%s".as_ptr(),
|
||||
name.as_ptr() as *mut libc::c_void,
|
||||
);
|
||||
debug_assert_eq!(res, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))]
|
||||
pub fn set_name(name: &CStr) {
|
||||
weak!(
|
||||
fn pthread_setname_np(
|
||||
thread: libc::pthread_t,
|
||||
name: *const libc::c_char,
|
||||
) -> libc::c_int;
|
||||
);
|
||||
|
||||
if let Some(f) = pthread_setname_np.get() {
|
||||
#[cfg(target_os = "nto")]
|
||||
const THREAD_NAME_MAX: usize = libc::_NTO_THREAD_NAME_MAX as usize;
|
||||
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
|
||||
const THREAD_NAME_MAX: usize = 32;
|
||||
|
||||
let name = truncate_cstr::<{ THREAD_NAME_MAX }>(name);
|
||||
let res = unsafe { f(libc::pthread_self(), name.as_ptr()) };
|
||||
debug_assert_eq!(res, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "fuchsia")]
|
||||
pub fn set_name(name: &CStr) {
|
||||
use super::fuchsia::*;
|
||||
unsafe {
|
||||
zx_object_set_property(
|
||||
zx_thread_self(),
|
||||
ZX_PROP_NAME,
|
||||
name.as_ptr() as *const libc::c_void,
|
||||
name.to_bytes().len(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "haiku")]
|
||||
pub fn set_name(name: &CStr) {
|
||||
unsafe {
|
||||
let thread_self = libc::find_thread(ptr::null_mut());
|
||||
let res = libc::rename_thread(thread_self, name.as_ptr());
|
||||
// We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
|
||||
debug_assert_eq!(res, libc::B_OK);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "vxworks")]
|
||||
pub fn set_name(name: &CStr) {
|
||||
let mut name = truncate_cstr::<{ (libc::VX_TASK_RENAME_LENGTH - 1) as usize }>(name);
|
||||
let res = unsafe { libc::taskNameSet(libc::taskIdSelf(), name.as_mut_ptr()) };
|
||||
debug_assert_eq!(res, libc::OK);
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_env = "newlib",
|
||||
target_os = "l4re",
|
||||
target_os = "emscripten",
|
||||
target_os = "redox",
|
||||
target_os = "hurd",
|
||||
target_os = "aix",
|
||||
))]
|
||||
pub fn set_name(_name: &CStr) {
|
||||
// Newlib and Emscripten have no way to set a thread name.
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "espidf"))]
|
||||
pub fn sleep(dur: Duration) {
|
||||
let mut secs = dur.as_secs();
|
||||
let mut nsecs = dur.subsec_nanos() as _;
|
||||
|
||||
// If we're awoken with a signal then the return value will be -1 and
|
||||
// nanosleep will fill in `ts` with the remaining time.
|
||||
unsafe {
|
||||
while secs > 0 || nsecs > 0 {
|
||||
let mut ts = libc::timespec {
|
||||
tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t,
|
||||
tv_nsec: nsecs,
|
||||
};
|
||||
secs -= ts.tv_sec as u64;
|
||||
let ts_ptr = &raw mut ts;
|
||||
if libc::nanosleep(ts_ptr, ts_ptr) == -1 {
|
||||
assert_eq!(os::errno(), libc::EINTR);
|
||||
secs += ts.tv_sec as u64;
|
||||
nsecs = ts.tv_nsec;
|
||||
} else {
|
||||
nsecs = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "espidf")]
|
||||
pub fn sleep(dur: Duration) {
|
||||
// ESP-IDF does not have `nanosleep`, so we use `usleep` instead.
|
||||
// As per the documentation of `usleep`, it is expected to support
|
||||
// sleep times as big as at least up to 1 second.
|
||||
//
|
||||
// ESP-IDF does support almost up to `u32::MAX`, but due to a potential integer overflow in its
|
||||
// `usleep` implementation
|
||||
// (https://github.com/espressif/esp-idf/blob/d7ca8b94c852052e3bc33292287ef4dd62c9eeb1/components/newlib/time.c#L210),
|
||||
// we limit the sleep time to the maximum one that would not cause the underlying `usleep` implementation to overflow
|
||||
// (`portTICK_PERIOD_MS` can be anything between 1 to 1000, and is 10 by default).
|
||||
const MAX_MICROS: u32 = u32::MAX - 1_000_000 - 1;
|
||||
|
||||
// Add any nanoseconds smaller than a microsecond as an extra microsecond
|
||||
// so as to comply with the `std::thread::sleep` contract which mandates
|
||||
// implementations to sleep for _at least_ the provided `dur`.
|
||||
// We can't overflow `micros` as it is a `u128`, while `Duration` is a pair of
|
||||
// (`u64` secs, `u32` nanos), where the nanos are strictly smaller than 1 second
|
||||
// (i.e. < 1_000_000_000)
|
||||
let mut micros = dur.as_micros() + if dur.subsec_nanos() % 1_000 > 0 { 1 } else { 0 };
|
||||
|
||||
while micros > 0 {
|
||||
let st = if micros > MAX_MICROS as u128 { MAX_MICROS } else { micros as u32 };
|
||||
unsafe {
|
||||
libc::usleep(st);
|
||||
}
|
||||
|
||||
micros -= st as u128;
|
||||
}
|
||||
}
|
||||
|
||||
// Any unix that has clock_nanosleep
|
||||
// If this list changes update the MIRI chock_nanosleep shim
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "dragonfly",
|
||||
target_os = "hurd",
|
||||
target_os = "fuchsia",
|
||||
target_os = "vxworks",
|
||||
))]
|
||||
pub fn sleep_until(deadline: Instant) {
|
||||
let Some(ts) = deadline.into_inner().into_timespec().to_timespec() else {
|
||||
// The deadline is further in the future then can be passed to
|
||||
// clock_nanosleep. We have to use Self::sleep instead. This might
|
||||
// happen on 32 bit platforms, especially closer to 2038.
|
||||
let now = Instant::now();
|
||||
if let Some(delay) = deadline.checked_duration_since(now) {
|
||||
Self::sleep(delay);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
unsafe {
|
||||
// When we get interrupted (res = EINTR) call clock_nanosleep again
|
||||
loop {
|
||||
let res = libc::clock_nanosleep(
|
||||
super::time::Instant::CLOCK_ID,
|
||||
libc::TIMER_ABSTIME,
|
||||
&ts,
|
||||
core::ptr::null_mut(), // not required with TIMER_ABSTIME
|
||||
);
|
||||
|
||||
if res == 0 {
|
||||
break;
|
||||
} else {
|
||||
assert_eq!(
|
||||
res,
|
||||
libc::EINTR,
|
||||
"timespec is in range,
|
||||
clockid is valid and kernel should support it"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Any unix that does not have clock_nanosleep
|
||||
#[cfg(not(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "dragonfly",
|
||||
target_os = "hurd",
|
||||
target_os = "fuchsia",
|
||||
target_os = "vxworks",
|
||||
)))]
|
||||
pub fn sleep_until(deadline: Instant) {
|
||||
let now = Instant::now();
|
||||
if let Some(delay) = deadline.checked_duration_since(now) {
|
||||
Self::sleep(delay);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join(self) {
|
||||
let id = self.into_id();
|
||||
let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
|
|
@ -410,84 +151,6 @@ impl Drop for Thread {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn current_os_id() -> Option<u64> {
|
||||
// Most Unix platforms have a way to query an integer ID of the current thread, all with
|
||||
// slightly different spellings.
|
||||
//
|
||||
// The OS thread ID is used rather than `pthread_self` so as to match what will be displayed
|
||||
// for process inspection (debuggers, trace, `top`, etc.).
|
||||
cfg_select! {
|
||||
// Most platforms have a function returning a `pid_t` or int, which is an `i32`.
|
||||
any(target_os = "android", target_os = "linux") => {
|
||||
use crate::sys::weak::syscall;
|
||||
|
||||
// `libc::gettid` is only available on glibc 2.30+, but the syscall is available
|
||||
// since Linux 2.4.11.
|
||||
syscall!(fn gettid() -> libc::pid_t;);
|
||||
|
||||
// SAFETY: FFI call with no preconditions.
|
||||
let id: libc::pid_t = unsafe { gettid() };
|
||||
Some(id as u64)
|
||||
}
|
||||
target_os = "nto" => {
|
||||
// SAFETY: FFI call with no preconditions.
|
||||
let id: libc::pid_t = unsafe { libc::gettid() };
|
||||
Some(id as u64)
|
||||
}
|
||||
target_os = "openbsd" => {
|
||||
// SAFETY: FFI call with no preconditions.
|
||||
let id: libc::pid_t = unsafe { libc::getthrid() };
|
||||
Some(id as u64)
|
||||
}
|
||||
target_os = "freebsd" => {
|
||||
// SAFETY: FFI call with no preconditions.
|
||||
let id: libc::c_int = unsafe { libc::pthread_getthreadid_np() };
|
||||
Some(id as u64)
|
||||
}
|
||||
target_os = "netbsd" => {
|
||||
// SAFETY: FFI call with no preconditions.
|
||||
let id: libc::lwpid_t = unsafe { libc::_lwp_self() };
|
||||
Some(id as u64)
|
||||
}
|
||||
any(target_os = "illumos", target_os = "solaris") => {
|
||||
// On Illumos and Solaris, the `pthread_t` is the same as the OS thread ID.
|
||||
// SAFETY: FFI call with no preconditions.
|
||||
let id: libc::pthread_t = unsafe { libc::pthread_self() };
|
||||
Some(id as u64)
|
||||
}
|
||||
target_vendor = "apple" => {
|
||||
// Apple allows querying arbitrary thread IDs, `thread=NULL` queries the current thread.
|
||||
let mut id = 0u64;
|
||||
// SAFETY: `thread_id` is a valid pointer, no other preconditions.
|
||||
let status: libc::c_int = unsafe { libc::pthread_threadid_np(0, &mut id) };
|
||||
if status == 0 {
|
||||
Some(id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
// Other platforms don't have an OS thread ID or don't have a way to access it.
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "nto",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "vxworks",
|
||||
target_os = "cygwin",
|
||||
target_vendor = "apple",
|
||||
))]
|
||||
fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] {
|
||||
let mut result = [0; MAX_WITH_NUL];
|
||||
for (src, dst) in cstr.to_bytes().iter().zip(&mut result[..MAX_WITH_NUL - 1]) {
|
||||
*dst = *src as libc::c_char;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
|
||||
cfg_select! {
|
||||
any(
|
||||
|
|
@ -668,6 +331,318 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn current_os_id() -> Option<u64> {
|
||||
// Most Unix platforms have a way to query an integer ID of the current thread, all with
|
||||
// slightly different spellings.
|
||||
//
|
||||
// The OS thread ID is used rather than `pthread_self` so as to match what will be displayed
|
||||
// for process inspection (debuggers, trace, `top`, etc.).
|
||||
cfg_select! {
|
||||
// Most platforms have a function returning a `pid_t` or int, which is an `i32`.
|
||||
any(target_os = "android", target_os = "linux") => {
|
||||
use crate::sys::pal::weak::syscall;
|
||||
|
||||
// `libc::gettid` is only available on glibc 2.30+, but the syscall is available
|
||||
// since Linux 2.4.11.
|
||||
syscall!(fn gettid() -> libc::pid_t;);
|
||||
|
||||
// SAFETY: FFI call with no preconditions.
|
||||
let id: libc::pid_t = unsafe { gettid() };
|
||||
Some(id as u64)
|
||||
}
|
||||
target_os = "nto" => {
|
||||
// SAFETY: FFI call with no preconditions.
|
||||
let id: libc::pid_t = unsafe { libc::gettid() };
|
||||
Some(id as u64)
|
||||
}
|
||||
target_os = "openbsd" => {
|
||||
// SAFETY: FFI call with no preconditions.
|
||||
let id: libc::pid_t = unsafe { libc::getthrid() };
|
||||
Some(id as u64)
|
||||
}
|
||||
target_os = "freebsd" => {
|
||||
// SAFETY: FFI call with no preconditions.
|
||||
let id: libc::c_int = unsafe { libc::pthread_getthreadid_np() };
|
||||
Some(id as u64)
|
||||
}
|
||||
target_os = "netbsd" => {
|
||||
// SAFETY: FFI call with no preconditions.
|
||||
let id: libc::lwpid_t = unsafe { libc::_lwp_self() };
|
||||
Some(id as u64)
|
||||
}
|
||||
any(target_os = "illumos", target_os = "solaris") => {
|
||||
// On Illumos and Solaris, the `pthread_t` is the same as the OS thread ID.
|
||||
// SAFETY: FFI call with no preconditions.
|
||||
let id: libc::pthread_t = unsafe { libc::pthread_self() };
|
||||
Some(id as u64)
|
||||
}
|
||||
target_vendor = "apple" => {
|
||||
// Apple allows querying arbitrary thread IDs, `thread=NULL` queries the current thread.
|
||||
let mut id = 0u64;
|
||||
// SAFETY: `thread_id` is a valid pointer, no other preconditions.
|
||||
let status: libc::c_int = unsafe { libc::pthread_threadid_np(0, &mut id) };
|
||||
if status == 0 {
|
||||
Some(id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
// Other platforms don't have an OS thread ID or don't have a way to access it.
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "nto",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "vxworks",
|
||||
target_os = "cygwin",
|
||||
target_vendor = "apple",
|
||||
))]
|
||||
fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] {
|
||||
let mut result = [0; MAX_WITH_NUL];
|
||||
for (src, dst) in cstr.to_bytes().iter().zip(&mut result[..MAX_WITH_NUL - 1]) {
|
||||
*dst = *src as libc::c_char;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
pub fn set_name(name: &CStr) {
|
||||
const PR_SET_NAME: libc::c_int = 15;
|
||||
unsafe {
|
||||
let res = libc::prctl(
|
||||
PR_SET_NAME,
|
||||
name.as_ptr(),
|
||||
0 as libc::c_ulong,
|
||||
0 as libc::c_ulong,
|
||||
0 as libc::c_ulong,
|
||||
);
|
||||
// We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
|
||||
debug_assert_eq!(res, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "nuttx",
|
||||
target_os = "cygwin"
|
||||
))]
|
||||
pub fn set_name(name: &CStr) {
|
||||
unsafe {
|
||||
cfg_select! {
|
||||
any(target_os = "linux", target_os = "cygwin") => {
|
||||
// Linux and Cygwin limits the allowed length of the name.
|
||||
const TASK_COMM_LEN: usize = 16;
|
||||
let name = truncate_cstr::<{ TASK_COMM_LEN }>(name);
|
||||
}
|
||||
_ => {
|
||||
// FreeBSD, DragonFly BSD and NuttX do not enforce length limits.
|
||||
}
|
||||
};
|
||||
// Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20 for Linux,
|
||||
// FreeBSD 12.2 and 13.0, and DragonFly BSD 6.0.
|
||||
let res = libc::pthread_setname_np(libc::pthread_self(), name.as_ptr());
|
||||
// We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
|
||||
debug_assert_eq!(res, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "openbsd")]
|
||||
pub fn set_name(name: &CStr) {
|
||||
unsafe {
|
||||
libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_vendor = "apple")]
|
||||
pub fn set_name(name: &CStr) {
|
||||
unsafe {
|
||||
let name = truncate_cstr::<{ libc::MAXTHREADNAMESIZE }>(name);
|
||||
let res = libc::pthread_setname_np(name.as_ptr());
|
||||
// We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
|
||||
debug_assert_eq!(res, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "netbsd")]
|
||||
pub fn set_name(name: &CStr) {
|
||||
unsafe {
|
||||
let res = libc::pthread_setname_np(
|
||||
libc::pthread_self(),
|
||||
c"%s".as_ptr(),
|
||||
name.as_ptr() as *mut libc::c_void,
|
||||
);
|
||||
debug_assert_eq!(res, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))]
|
||||
pub fn set_name(name: &CStr) {
|
||||
weak!(
|
||||
fn pthread_setname_np(thread: libc::pthread_t, name: *const libc::c_char) -> libc::c_int;
|
||||
);
|
||||
|
||||
if let Some(f) = pthread_setname_np.get() {
|
||||
#[cfg(target_os = "nto")]
|
||||
const THREAD_NAME_MAX: usize = libc::_NTO_THREAD_NAME_MAX as usize;
|
||||
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
|
||||
const THREAD_NAME_MAX: usize = 32;
|
||||
|
||||
let name = truncate_cstr::<{ THREAD_NAME_MAX }>(name);
|
||||
let res = unsafe { f(libc::pthread_self(), name.as_ptr()) };
|
||||
debug_assert_eq!(res, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "fuchsia")]
|
||||
pub fn set_name(name: &CStr) {
|
||||
use crate::sys::pal::fuchsia::*;
|
||||
unsafe {
|
||||
zx_object_set_property(
|
||||
zx_thread_self(),
|
||||
ZX_PROP_NAME,
|
||||
name.as_ptr() as *const libc::c_void,
|
||||
name.to_bytes().len(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "haiku")]
|
||||
pub fn set_name(name: &CStr) {
|
||||
unsafe {
|
||||
let thread_self = libc::find_thread(ptr::null_mut());
|
||||
let res = libc::rename_thread(thread_self, name.as_ptr());
|
||||
// We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
|
||||
debug_assert_eq!(res, libc::B_OK);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "vxworks")]
|
||||
pub fn set_name(name: &CStr) {
|
||||
let mut name = truncate_cstr::<{ (libc::VX_TASK_RENAME_LENGTH - 1) as usize }>(name);
|
||||
let res = unsafe { libc::taskNameSet(libc::taskIdSelf(), name.as_mut_ptr()) };
|
||||
debug_assert_eq!(res, libc::OK);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "espidf"))]
|
||||
pub fn sleep(dur: Duration) {
|
||||
let mut secs = dur.as_secs();
|
||||
let mut nsecs = dur.subsec_nanos() as _;
|
||||
|
||||
// If we're awoken with a signal then the return value will be -1 and
|
||||
// nanosleep will fill in `ts` with the remaining time.
|
||||
unsafe {
|
||||
while secs > 0 || nsecs > 0 {
|
||||
let mut ts = libc::timespec {
|
||||
tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t,
|
||||
tv_nsec: nsecs,
|
||||
};
|
||||
secs -= ts.tv_sec as u64;
|
||||
let ts_ptr = &raw mut ts;
|
||||
if libc::nanosleep(ts_ptr, ts_ptr) == -1 {
|
||||
assert_eq!(os::errno(), libc::EINTR);
|
||||
secs += ts.tv_sec as u64;
|
||||
nsecs = ts.tv_nsec;
|
||||
} else {
|
||||
nsecs = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "espidf")]
|
||||
pub fn sleep(dur: Duration) {
|
||||
// ESP-IDF does not have `nanosleep`, so we use `usleep` instead.
|
||||
// As per the documentation of `usleep`, it is expected to support
|
||||
// sleep times as big as at least up to 1 second.
|
||||
//
|
||||
// ESP-IDF does support almost up to `u32::MAX`, but due to a potential integer overflow in its
|
||||
// `usleep` implementation
|
||||
// (https://github.com/espressif/esp-idf/blob/d7ca8b94c852052e3bc33292287ef4dd62c9eeb1/components/newlib/time.c#L210),
|
||||
// we limit the sleep time to the maximum one that would not cause the underlying `usleep` implementation to overflow
|
||||
// (`portTICK_PERIOD_MS` can be anything between 1 to 1000, and is 10 by default).
|
||||
const MAX_MICROS: u32 = u32::MAX - 1_000_000 - 1;
|
||||
|
||||
// Add any nanoseconds smaller than a microsecond as an extra microsecond
|
||||
// so as to comply with the `std::thread::sleep` contract which mandates
|
||||
// implementations to sleep for _at least_ the provided `dur`.
|
||||
// We can't overflow `micros` as it is a `u128`, while `Duration` is a pair of
|
||||
// (`u64` secs, `u32` nanos), where the nanos are strictly smaller than 1 second
|
||||
// (i.e. < 1_000_000_000)
|
||||
let mut micros = dur.as_micros() + if dur.subsec_nanos() % 1_000 > 0 { 1 } else { 0 };
|
||||
|
||||
while micros > 0 {
|
||||
let st = if micros > MAX_MICROS as u128 { MAX_MICROS } else { micros as u32 };
|
||||
unsafe {
|
||||
libc::usleep(st);
|
||||
}
|
||||
|
||||
micros -= st as u128;
|
||||
}
|
||||
}
|
||||
|
||||
// Any unix that has clock_nanosleep
|
||||
// If this list changes update the MIRI chock_nanosleep shim
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "linux",
|
||||
target_os = "android",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
target_os = "dragonfly",
|
||||
target_os = "hurd",
|
||||
target_os = "fuchsia",
|
||||
target_os = "vxworks",
|
||||
))]
|
||||
pub fn sleep_until(deadline: crate::time::Instant) {
|
||||
use crate::time::Instant;
|
||||
|
||||
let Some(ts) = deadline.into_inner().into_timespec().to_timespec() else {
|
||||
// The deadline is further in the future then can be passed to
|
||||
// clock_nanosleep. We have to use Self::sleep instead. This might
|
||||
// happen on 32 bit platforms, especially closer to 2038.
|
||||
let now = Instant::now();
|
||||
if let Some(delay) = deadline.checked_duration_since(now) {
|
||||
sleep(delay);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
unsafe {
|
||||
// When we get interrupted (res = EINTR) call clock_nanosleep again
|
||||
loop {
|
||||
let res = libc::clock_nanosleep(
|
||||
crate::sys::time::Instant::CLOCK_ID,
|
||||
libc::TIMER_ABSTIME,
|
||||
&ts,
|
||||
core::ptr::null_mut(), // not required with TIMER_ABSTIME
|
||||
);
|
||||
|
||||
if res == 0 {
|
||||
break;
|
||||
} else {
|
||||
assert_eq!(
|
||||
res,
|
||||
libc::EINTR,
|
||||
"timespec is in range,
|
||||
clockid is valid and kernel should support it"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
let ret = unsafe { libc::sched_yield() };
|
||||
debug_assert_eq!(ret, 0);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
mod cgroups {
|
||||
//! Currently not covered
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
use super::unsupported;
|
||||
use crate::ffi::CStr;
|
||||
use crate::io;
|
||||
use crate::num::NonZero;
|
||||
use crate::time::{Duration, Instant};
|
||||
use crate::time::Duration;
|
||||
|
||||
pub struct Thread(!);
|
||||
|
||||
|
|
@ -15,23 +14,7 @@ impl Thread {
|
|||
_name: Option<&str>,
|
||||
_p: Box<dyn FnOnce()>,
|
||||
) -> io::Result<Thread> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
pub fn set_name(_name: &CStr) {
|
||||
// nope
|
||||
}
|
||||
|
||||
pub fn sleep(_dur: Duration) {
|
||||
panic!("can't sleep");
|
||||
}
|
||||
|
||||
pub fn sleep_until(_deadline: Instant) {
|
||||
panic!("can't sleep");
|
||||
Err(io::Error::UNSUPPORTED_PLATFORM)
|
||||
}
|
||||
|
||||
pub fn join(self) {
|
||||
|
|
@ -39,10 +22,22 @@ impl Thread {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn current_os_id() -> Option<u64> {
|
||||
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
|
||||
Err(io::Error::UNKNOWN_THREAD_COUNT)
|
||||
}
|
||||
|
||||
pub fn current_os_id() -> Option<u64> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
|
||||
unsupported()
|
||||
pub fn yield_now() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
pub fn set_name(_name: &CStr) {
|
||||
// nope
|
||||
}
|
||||
|
||||
pub fn sleep(_dur: Duration) {
|
||||
panic!("can't sleep");
|
||||
}
|
||||
185
library/std/src/sys/thread/wasip1.rs
Normal file
185
library/std/src/sys/thread/wasip1.rs
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
#![forbid(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
#[cfg(target_feature = "atomics")]
|
||||
use crate::io;
|
||||
use crate::mem;
|
||||
#[cfg(target_feature = "atomics")]
|
||||
use crate::num::NonZero;
|
||||
#[cfg(target_feature = "atomics")]
|
||||
use crate::sys::os;
|
||||
use crate::time::Duration;
|
||||
#[cfg(target_feature = "atomics")]
|
||||
use crate::{cmp, ptr};
|
||||
|
||||
// Add a few symbols not in upstream `libc` just yet.
|
||||
#[cfg(target_feature = "atomics")]
|
||||
mod libc {
|
||||
pub use libc::*;
|
||||
|
||||
pub use crate::ffi;
|
||||
|
||||
// defined in wasi-libc
|
||||
// https://github.com/WebAssembly/wasi-libc/blob/a6f871343313220b76009827ed0153586361c0d5/libc-top-half/musl/include/alltypes.h.in#L108
|
||||
#[repr(C)]
|
||||
union pthread_attr_union {
|
||||
__i: [ffi::c_int; if size_of::<ffi::c_long>() == 8 { 14 } else { 9 }],
|
||||
__vi: [ffi::c_int; if size_of::<ffi::c_long>() == 8 { 14 } else { 9 }],
|
||||
__s: [ffi::c_ulong; if size_of::<ffi::c_long>() == 8 { 7 } else { 9 }],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct pthread_attr_t {
|
||||
__u: pthread_attr_union,
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type pthread_t = *mut ffi::c_void;
|
||||
|
||||
pub const _SC_NPROCESSORS_ONLN: ffi::c_int = 84;
|
||||
|
||||
unsafe extern "C" {
|
||||
pub fn pthread_create(
|
||||
native: *mut pthread_t,
|
||||
attr: *const pthread_attr_t,
|
||||
f: extern "C" fn(*mut ffi::c_void) -> *mut ffi::c_void,
|
||||
value: *mut ffi::c_void,
|
||||
) -> ffi::c_int;
|
||||
pub fn pthread_join(native: pthread_t, value: *mut *mut ffi::c_void) -> ffi::c_int;
|
||||
pub fn pthread_attr_init(attrp: *mut pthread_attr_t) -> ffi::c_int;
|
||||
pub fn pthread_attr_setstacksize(
|
||||
attr: *mut pthread_attr_t,
|
||||
stack_size: libc::size_t,
|
||||
) -> ffi::c_int;
|
||||
pub fn pthread_attr_destroy(attr: *mut pthread_attr_t) -> ffi::c_int;
|
||||
pub fn pthread_detach(thread: pthread_t) -> ffi::c_int;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_feature = "atomics")]
|
||||
pub struct Thread {
|
||||
id: libc::pthread_t,
|
||||
}
|
||||
|
||||
#[cfg(target_feature = "atomics")]
|
||||
impl Drop for Thread {
|
||||
fn drop(&mut self) {
|
||||
let ret = unsafe { libc::pthread_detach(self.id) };
|
||||
debug_assert_eq!(ret, 0);
|
||||
}
|
||||
}
|
||||
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
|
||||
|
||||
#[cfg(target_feature = "atomics")]
|
||||
impl Thread {
|
||||
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
|
||||
pub unsafe fn new(
|
||||
stack: usize,
|
||||
_name: Option<&str>,
|
||||
p: Box<dyn FnOnce()>,
|
||||
) -> io::Result<Thread> {
|
||||
let p = Box::into_raw(Box::new(p));
|
||||
let mut native: libc::pthread_t = unsafe { mem::zeroed() };
|
||||
let mut attr: libc::pthread_attr_t = unsafe { mem::zeroed() };
|
||||
assert_eq!(unsafe { libc::pthread_attr_init(&mut attr) }, 0);
|
||||
|
||||
let stack_size = cmp::max(stack, DEFAULT_MIN_STACK_SIZE);
|
||||
|
||||
match unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) } {
|
||||
0 => {}
|
||||
n => {
|
||||
assert_eq!(n, libc::EINVAL);
|
||||
// EINVAL means |stack_size| is either too small or not a
|
||||
// multiple of the system page size. Because it's definitely
|
||||
// >= PTHREAD_STACK_MIN, it must be an alignment issue.
|
||||
// Round up to the nearest page and try again.
|
||||
let page_size = os::page_size();
|
||||
let stack_size =
|
||||
(stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1);
|
||||
assert_eq!(unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) }, 0);
|
||||
}
|
||||
};
|
||||
|
||||
let ret = unsafe { libc::pthread_create(&mut native, &attr, thread_start, p as *mut _) };
|
||||
// Note: if the thread creation fails and this assert fails, then p will
|
||||
// be leaked. However, an alternative design could cause double-free
|
||||
// which is clearly worse.
|
||||
assert_eq!(unsafe { libc::pthread_attr_destroy(&mut attr) }, 0);
|
||||
|
||||
return if ret != 0 {
|
||||
// The thread failed to start and as a result p was not consumed. Therefore, it is
|
||||
// safe to reconstruct the box so that it gets deallocated.
|
||||
unsafe {
|
||||
drop(Box::from_raw(p));
|
||||
}
|
||||
Err(io::Error::from_raw_os_error(ret))
|
||||
} else {
|
||||
Ok(Thread { id: native })
|
||||
};
|
||||
|
||||
extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
|
||||
unsafe {
|
||||
// Finally, let's run some code.
|
||||
Box::from_raw(main as *mut Box<dyn FnOnce()>)();
|
||||
}
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join(self) {
|
||||
let id = mem::ManuallyDrop::new(self).id;
|
||||
let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
if ret != 0 {
|
||||
rtabort!("failed to join thread: {}", io::Error::from_raw_os_error(ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_feature = "atomics")]
|
||||
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
|
||||
match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
|
||||
-1 => Err(io::Error::last_os_error()),
|
||||
cpus => NonZero::new(cpus as usize).ok_or(io::Error::UNKNOWN_THREAD_COUNT),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
let ret = unsafe { wasi::sched_yield() };
|
||||
debug_assert_eq!(ret, Ok(()));
|
||||
}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
let mut nanos = dur.as_nanos();
|
||||
while nanos > 0 {
|
||||
const USERDATA: wasi::Userdata = 0x0123_45678;
|
||||
|
||||
let clock = wasi::SubscriptionClock {
|
||||
id: wasi::CLOCKID_MONOTONIC,
|
||||
timeout: u64::try_from(nanos).unwrap_or(u64::MAX),
|
||||
precision: 0,
|
||||
flags: 0,
|
||||
};
|
||||
nanos -= u128::from(clock.timeout);
|
||||
|
||||
let in_ = wasi::Subscription {
|
||||
userdata: USERDATA,
|
||||
u: wasi::SubscriptionU { tag: 0, u: wasi::SubscriptionUU { clock } },
|
||||
};
|
||||
unsafe {
|
||||
let mut event: wasi::Event = mem::zeroed();
|
||||
let res = wasi::poll_oneoff(&in_, &mut event, 1);
|
||||
match (res, event) {
|
||||
(
|
||||
Ok(1),
|
||||
wasi::Event {
|
||||
userdata: USERDATA,
|
||||
error: wasi::ERRNO_SUCCESS,
|
||||
type_: wasi::EVENTTYPE_CLOCK,
|
||||
..
|
||||
},
|
||||
) => {}
|
||||
_ => panic!("thread::sleep(): unexpected result of poll_oneoff"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
32
library/std/src/sys/thread/wasip2.rs
Normal file
32
library/std/src/sys/thread/wasip2.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
use crate::time::{Duration, Instant};
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
// Sleep in increments of `u64::MAX` nanoseconds until the `dur` is
|
||||
// entirely drained.
|
||||
let mut remaining = dur.as_nanos();
|
||||
while remaining > 0 {
|
||||
let amt = u64::try_from(remaining).unwrap_or(u64::MAX);
|
||||
wasip2::clocks::monotonic_clock::subscribe_duration(amt).block();
|
||||
remaining -= u128::from(amt);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sleep_until(deadline: Instant) {
|
||||
match u64::try_from(deadline.into_inner().as_duration().as_nanos()) {
|
||||
// If the point in time we're sleeping to fits within a 64-bit
|
||||
// number of nanoseconds then directly use `subscribe_instant`.
|
||||
Ok(deadline) => {
|
||||
wasip2::clocks::monotonic_clock::subscribe_instant(deadline).block();
|
||||
}
|
||||
// ... otherwise we're sleeping for 500+ years relative to the
|
||||
// "start" of what the system is using as a clock so speed/accuracy
|
||||
// is not so much of a concern. Use `sleep` instead.
|
||||
Err(_) => {
|
||||
let now = Instant::now();
|
||||
|
||||
if let Some(delay) = deadline.checked_duration_since(now) {
|
||||
sleep(delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
library/std/src/sys/thread/wasm.rs
Normal file
23
library/std/src/sys/thread/wasm.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
use crate::cmp;
|
||||
use crate::time::Duration;
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use core::arch::wasm32 as wasm;
|
||||
#[cfg(target_arch = "wasm64")]
|
||||
use core::arch::wasm64 as wasm;
|
||||
|
||||
// Use an atomic wait to block the current thread artificially with a
|
||||
// timeout listed. Note that we should never be notified (return value
|
||||
// of 0) or our comparison should never fail (return value of 1) so we
|
||||
// should always only resume execution through a timeout (return value
|
||||
// 2).
|
||||
let mut nanos = dur.as_nanos();
|
||||
while nanos > 0 {
|
||||
let amt = cmp::min(i64::MAX as u128, nanos);
|
||||
let mut x = 0;
|
||||
let val = unsafe { wasm::memory_atomic_wait32(&mut x, 0, amt as i64) };
|
||||
debug_assert_eq!(val, 2);
|
||||
nanos -= amt;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
use core::ffi::c_void;
|
||||
|
||||
use super::time::WaitableTimer;
|
||||
use super::to_u16s;
|
||||
use crate::ffi::CStr;
|
||||
use crate::num::NonZero;
|
||||
use crate::os::windows::io::{AsRawHandle, HandleOrNull};
|
||||
use crate::sys::handle::Handle;
|
||||
use crate::sys::pal::time::WaitableTimer;
|
||||
use crate::sys::pal::{dur2timeout, to_u16s};
|
||||
use crate::sys::{c, stack_overflow};
|
||||
use crate::sys_common::FromInner;
|
||||
use crate::time::{Duration, Instant};
|
||||
use crate::time::Duration;
|
||||
use crate::{io, ptr};
|
||||
|
||||
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
|
||||
|
|
@ -62,24 +62,6 @@ impl Thread {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_name(name: &CStr) {
|
||||
if let Ok(utf8) = name.to_str() {
|
||||
if let Ok(utf16) = to_u16s(utf8) {
|
||||
unsafe {
|
||||
// SAFETY: the vec returned by `to_u16s` ends with a zero value
|
||||
Self::set_name_wide(&utf16)
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// `name` must end with a zero value
|
||||
pub unsafe fn set_name_wide(name: &[u16]) {
|
||||
unsafe { c::SetThreadDescription(c::GetCurrentThread(), name.as_ptr()) };
|
||||
}
|
||||
|
||||
pub fn join(self) {
|
||||
let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) };
|
||||
if rc == c::WAIT_FAILED {
|
||||
|
|
@ -87,37 +69,6 @@ impl Thread {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
// This function will return 0 if there are no other threads to execute,
|
||||
// but this also means that the yield was useless so this isn't really a
|
||||
// case that needs to be worried about.
|
||||
unsafe {
|
||||
c::SwitchToThread();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
fn high_precision_sleep(dur: Duration) -> Result<(), ()> {
|
||||
let timer = WaitableTimer::high_resolution()?;
|
||||
timer.set(dur)?;
|
||||
timer.wait()
|
||||
}
|
||||
// Attempt to use high-precision sleep (Windows 10, version 1803+).
|
||||
// On error fallback to the standard `Sleep` function.
|
||||
// Also preserves the zero duration behavior of `Sleep`.
|
||||
if dur.is_zero() || high_precision_sleep(dur).is_err() {
|
||||
unsafe { c::Sleep(super::dur2timeout(dur)) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sleep_until(deadline: Instant) {
|
||||
let now = Instant::now();
|
||||
|
||||
if let Some(delay) = deadline.checked_duration_since(now) {
|
||||
Self::sleep(delay);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle(&self) -> &Handle {
|
||||
&self.handle
|
||||
}
|
||||
|
|
@ -127,14 +78,6 @@ impl Thread {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn current_os_id() -> Option<u64> {
|
||||
// SAFETY: FFI call with no preconditions.
|
||||
let id: u32 = unsafe { c::GetCurrentThreadId() };
|
||||
|
||||
// A return value of 0 indicates failed lookup.
|
||||
if id == 0 { None } else { Some(id.into()) }
|
||||
}
|
||||
|
||||
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
|
||||
let res = unsafe {
|
||||
let mut sysinfo: c::SYSTEM_INFO = crate::mem::zeroed();
|
||||
|
|
@ -146,3 +89,52 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
|
|||
cpus => Ok(unsafe { NonZero::new_unchecked(cpus) }),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn current_os_id() -> Option<u64> {
|
||||
// SAFETY: FFI call with no preconditions.
|
||||
let id: u32 = unsafe { c::GetCurrentThreadId() };
|
||||
|
||||
// A return value of 0 indicates failed lookup.
|
||||
if id == 0 { None } else { Some(id.into()) }
|
||||
}
|
||||
|
||||
pub fn set_name(name: &CStr) {
|
||||
if let Ok(utf8) = name.to_str() {
|
||||
if let Ok(utf16) = to_u16s(utf8) {
|
||||
unsafe {
|
||||
// SAFETY: the vec returned by `to_u16s` ends with a zero value
|
||||
set_name_wide(&utf16)
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// `name` must end with a zero value
|
||||
pub unsafe fn set_name_wide(name: &[u16]) {
|
||||
unsafe { c::SetThreadDescription(c::GetCurrentThread(), name.as_ptr()) };
|
||||
}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
fn high_precision_sleep(dur: Duration) -> Result<(), ()> {
|
||||
let timer = WaitableTimer::high_resolution()?;
|
||||
timer.set(dur)?;
|
||||
timer.wait()
|
||||
}
|
||||
// Attempt to use high-precision sleep (Windows 10, version 1803+).
|
||||
// On error fallback to the standard `Sleep` function.
|
||||
// Also preserves the zero duration behavior of `Sleep`.
|
||||
if dur.is_zero() || high_precision_sleep(dur).is_err() {
|
||||
unsafe { c::Sleep(dur2timeout(dur)) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
// This function will return 0 if there are no other threads to execute,
|
||||
// but this also means that the yield was useless so this isn't really a
|
||||
// case that needs to be worried about.
|
||||
unsafe {
|
||||
c::SwitchToThread();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
use core::arch::asm;
|
||||
|
||||
use crate::ffi::CStr;
|
||||
use crate::io;
|
||||
use crate::num::NonZero;
|
||||
use crate::os::xous::ffi::{
|
||||
|
|
@ -8,7 +7,7 @@ use crate::os::xous::ffi::{
|
|||
map_memory, update_memory_flags,
|
||||
};
|
||||
use crate::os::xous::services::{TicktimerScalar, ticktimer_server};
|
||||
use crate::time::{Duration, Instant};
|
||||
use crate::time::Duration;
|
||||
|
||||
pub struct Thread {
|
||||
tid: ThreadId,
|
||||
|
|
@ -110,46 +109,29 @@ impl Thread {
|
|||
Ok(Thread { tid })
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
do_yield();
|
||||
}
|
||||
|
||||
pub fn set_name(_name: &CStr) {
|
||||
// nope
|
||||
}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
// Because the sleep server works on units of `usized milliseconds`, split
|
||||
// the messages up into these chunks. This means we may run into issues
|
||||
// if you try to sleep a thread for more than 49 days on a 32-bit system.
|
||||
let mut millis = dur.as_millis();
|
||||
while millis > 0 {
|
||||
let sleep_duration =
|
||||
if millis > (usize::MAX as _) { usize::MAX } else { millis as usize };
|
||||
blocking_scalar(ticktimer_server(), TicktimerScalar::SleepMs(sleep_duration).into())
|
||||
.expect("failed to send message to ticktimer server");
|
||||
millis -= sleep_duration as u128;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sleep_until(deadline: Instant) {
|
||||
let now = Instant::now();
|
||||
|
||||
if let Some(delay) = deadline.checked_duration_since(now) {
|
||||
Self::sleep(delay);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn join(self) {
|
||||
join_thread(self.tid).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn current_os_id() -> Option<u64> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
|
||||
// We're unicore right now.
|
||||
Ok(unsafe { NonZero::new_unchecked(1) })
|
||||
}
|
||||
|
||||
pub fn yield_now() {
|
||||
do_yield();
|
||||
}
|
||||
|
||||
pub fn sleep(dur: Duration) {
|
||||
// Because the sleep server works on units of `usized milliseconds`, split
|
||||
// the messages up into these chunks. This means we may run into issues
|
||||
// if you try to sleep a thread for more than 49 days on a 32-bit system.
|
||||
let mut millis = dur.as_millis();
|
||||
while millis > 0 {
|
||||
let sleep_duration = if millis > (usize::MAX as _) { usize::MAX } else { millis as usize };
|
||||
blocking_scalar(ticktimer_server(), TicktimerScalar::SleepMs(sleep_duration).into())
|
||||
.expect("failed to send message to ticktimer server");
|
||||
millis -= sleep_duration as u128;
|
||||
}
|
||||
}
|
||||
|
|
@ -550,7 +550,7 @@ impl Builder {
|
|||
}
|
||||
|
||||
if let Some(name) = their_thread.cname() {
|
||||
imp::Thread::set_name(name);
|
||||
imp::set_name(name);
|
||||
}
|
||||
|
||||
let f = f.into_inner();
|
||||
|
|
@ -763,7 +763,7 @@ where
|
|||
/// [`Mutex`]: crate::sync::Mutex
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn yield_now() {
|
||||
imp::Thread::yield_now()
|
||||
imp::yield_now()
|
||||
}
|
||||
|
||||
/// Determines whether the current thread is unwinding because of panic.
|
||||
|
|
@ -884,7 +884,7 @@ pub fn sleep_ms(ms: u32) {
|
|||
/// ```
|
||||
#[stable(feature = "thread_sleep", since = "1.4.0")]
|
||||
pub fn sleep(dur: Duration) {
|
||||
imp::Thread::sleep(dur)
|
||||
imp::sleep(dur)
|
||||
}
|
||||
|
||||
/// Puts the current thread to sleep until the specified deadline has passed.
|
||||
|
|
@ -983,7 +983,7 @@ pub fn sleep(dur: Duration) {
|
|||
/// ```
|
||||
#[unstable(feature = "thread_sleep_until", issue = "113752")]
|
||||
pub fn sleep_until(deadline: Instant) {
|
||||
imp::Thread::sleep_until(deadline)
|
||||
imp::sleep_until(deadline)
|
||||
}
|
||||
|
||||
/// Used to ensure that `park` and `park_timeout` do not unwind, as that can
|
||||
|
|
|
|||
|
|
@ -95,8 +95,8 @@ target | notes
|
|||
`arm-unknown-linux-gnueabihf` | Armv6 Linux, hardfloat (kernel 3.2+, glibc 2.17)
|
||||
`armv7-unknown-linux-gnueabihf` | Armv7-A Linux, hardfloat (kernel 3.2+, glibc 2.17)
|
||||
[`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | Armv7-A OpenHarmony
|
||||
[`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, glibc 2.36)
|
||||
[`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, musl 1.2.5)
|
||||
[`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, glibc 2.36), LSX required
|
||||
[`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, musl 1.2.5), LSX required
|
||||
[`i686-pc-windows-gnu`](platform-support/windows-gnu.md) | 32-bit MinGW (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment]
|
||||
`powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2+, glibc 2.17)
|
||||
`powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2+, glibc 2.17)
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ LoongArch is a RISC ISA developed by Loongson Technology Corporation Limited.
|
|||
|
||||
| Target | Description |
|
||||
|--------|-------------|
|
||||
| `loongarch64-unknown-linux-gnu` | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36) |
|
||||
| `loongarch64-unknown-linux-musl` | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5) |
|
||||
| `loongarch64-unknown-linux-gnu` | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36), LSX required |
|
||||
| `loongarch64-unknown-linux-musl` | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5), LSX required |
|
||||
|
||||
These support both native and cross builds, and have full support for `std`.
|
||||
|
||||
|
|
@ -23,8 +23,6 @@ Reference material:
|
|||
## Target maintainers
|
||||
|
||||
[@heiher](https://github.com/heiher)
|
||||
[@xiangzhai](https://github.com/xiangzhai)
|
||||
[@zhaixiaojuan](https://github.com/zhaixiaojuan)
|
||||
[@xen0n](https://github.com/xen0n)
|
||||
|
||||
## Requirements
|
||||
|
|
@ -46,8 +44,8 @@ The targets require a reasonably up-to-date LoongArch toolchain on the host.
|
|||
Currently the following components are used by the Rust CI to build the target,
|
||||
and the versions can be seen as the minimum requirement:
|
||||
|
||||
* GNU Binutils 2.40
|
||||
* GCC 13.x
|
||||
* GNU Binutils 2.42
|
||||
* GCC 14.x
|
||||
* glibc 2.36
|
||||
* linux-headers 5.19
|
||||
|
||||
|
|
@ -59,6 +57,11 @@ for newer LoongArch ELF relocation types, among other features.
|
|||
Recent LLVM/Clang toolchains may be able to build the targets, but are not
|
||||
currently being actively tested.
|
||||
|
||||
### CPU features
|
||||
|
||||
These targets require the double-precision floating-point and LSX (LoongArch
|
||||
SIMD Extension) features.
|
||||
|
||||
## Building
|
||||
|
||||
These targets are distributed through `rustup`, and otherwise require no
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 19f0a49c5c3f4ba88b5e7ac620b9a0d8574c09cb
|
||||
Subproject commit 333793696b0a08002acac6af983adc7a5233fc56
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 761c4658d0079d607e6d33cf0c060e61a617cad3
|
||||
Subproject commit 24bb93c388fb8c211a37986539f24a819dc669d3
|
||||
|
|
@ -11,7 +11,7 @@ use rustc_ast::{BinOpKind, LitKind, RangeLimits};
|
|||
use rustc_data_structures::packed::Pu128;
|
||||
use rustc_data_structures::unhash::UnindexMap;
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_hir::{Body, Expr, ExprKind};
|
||||
use rustc_hir::{Block, Body, Expr, ExprKind, UnOp};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::source_map::Spanned;
|
||||
|
|
@ -135,12 +135,12 @@ fn assert_len_expr<'hir>(
|
|||
cx: &LateContext<'_>,
|
||||
expr: &'hir Expr<'hir>,
|
||||
) -> Option<(LengthComparison, usize, &'hir Expr<'hir>)> {
|
||||
let (cmp, asserted_len, slice_len) = if let Some(
|
||||
higher::IfLetOrMatch::Match(cond, [_, then], _)
|
||||
) = higher::IfLetOrMatch::parse(cx, expr)
|
||||
&& let ExprKind::Binary(bin_op, left, right) = &cond.kind
|
||||
let (cmp, asserted_len, slice_len) = if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr)
|
||||
&& let ExprKind::Unary(UnOp::Not, condition) = &cond.kind
|
||||
&& let ExprKind::Binary(bin_op, left, right) = &condition.kind
|
||||
// check if `then` block has a never type expression
|
||||
&& cx.typeck_results().expr_ty(then.body).is_never()
|
||||
&& let ExprKind::Block(Block { expr: Some(then_expr), .. }, _) = then.kind
|
||||
&& cx.typeck_results().expr_ty(then_expr).is_never()
|
||||
{
|
||||
len_comparison(bin_op.node, left, right)?
|
||||
} else if let Some((macro_call, bin_op)) = first_node_macro_backtrace(cx, expr).find_map(|macro_call| {
|
||||
|
|
|
|||
|
|
@ -196,7 +196,6 @@ fn issue_13106() {
|
|||
|
||||
const {
|
||||
assert!(EMPTY_STR.is_empty());
|
||||
//~^ const_is_empty
|
||||
}
|
||||
|
||||
const {
|
||||
|
|
|
|||
|
|
@ -158,16 +158,10 @@ LL | let _ = val.is_empty();
|
|||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: this expression always evaluates to true
|
||||
--> tests/ui/const_is_empty.rs:198:17
|
||||
|
|
||||
LL | assert!(EMPTY_STR.is_empty());
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: this expression always evaluates to true
|
||||
--> tests/ui/const_is_empty.rs:203:9
|
||||
--> tests/ui/const_is_empty.rs:202:9
|
||||
|
|
||||
LL | EMPTY_STR.is_empty();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 28 previous errors
|
||||
error: aborting due to 27 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#![warn(clippy::incompatible_msrv)]
|
||||
#![feature(custom_inner_attributes)]
|
||||
#![allow(stable_features, clippy::diverging_sub_expression)]
|
||||
#![allow(stable_features)]
|
||||
#![feature(strict_provenance)] // For use in test
|
||||
#![clippy::msrv = "1.3.0"]
|
||||
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@ LL | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _
|
|||
= note: inside closure at tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs:LL:CC
|
||||
|
||||
error: the evaluated program deadlocked
|
||||
--> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
--> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
|
|
||||
LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
| ^ this thread got stuck here
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
= note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
= note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
= note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
note: inside `main`
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@ LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu
|
|||
= note: inside closure at tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC
|
||||
|
||||
error: the evaluated program deadlocked
|
||||
--> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
--> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
|
|
||||
LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
| ^ this thread got stuck here
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
= note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
= note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
= note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
note: inside `main`
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@ LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu
|
|||
= note: inside closure at tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC
|
||||
|
||||
error: the evaluated program deadlocked
|
||||
--> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
--> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
|
|
||||
LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
| ^ this thread got stuck here
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
= note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
= note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
= note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
note: inside `main`
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: Undefined Behavior: trying to join a detached thread
|
||||
--> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
--> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
|
|
||||
LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
||||
|
|
@ -7,7 +7,7 @@ LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(
|
|||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
= note: BACKTRACE:
|
||||
= note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
= note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
= note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
= note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
note: inside `main`
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@ LL | assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), WAIT_OBJ
|
|||
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: the evaluated program deadlocked
|
||||
--> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
--> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
|
|
||||
LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) };
|
||||
| ^ this thread got stuck here
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
= note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
= note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
= note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
note: inside `main`
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@ LL | assert_eq!(WaitForSingleObject(native, INFINITE), WAIT_OBJECT_0
|
|||
= note: inside closure at tests/fail-dep/concurrency/windows_join_self.rs:LL:CC
|
||||
|
||||
error: the evaluated program deadlocked
|
||||
--> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
--> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
|
|
||||
LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) };
|
||||
| ^ this thread got stuck here
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
= note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
= note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
= note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
note: inside `main`
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
error: the evaluated program deadlocked
|
||||
--> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
--> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
|
|
||||
LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
| ^ this thread got stuck here
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
= note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
= note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
= note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
note: inside `main`
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
error: the evaluated program deadlocked
|
||||
--> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
--> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
|
|
||||
LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
| ^ this thread got stuck here
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
= note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
= note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
= note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
note: inside `main`
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ error: the evaluated program deadlocked
|
|||
= note: BACKTRACE on thread `unnamed-ID`:
|
||||
|
||||
error: the evaluated program deadlocked
|
||||
--> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
--> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
|
|
||||
LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
| ^ this thread got stuck here
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
= note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
= note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
= note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
note: inside `main`
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
error: the evaluated program deadlocked
|
||||
--> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
--> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
|
|
||||
LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
| ^ this thread got stuck here
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
= note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
= note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
= note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
note: inside `main`
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
error: the evaluated program deadlocked
|
||||
--> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
--> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
|
|
||||
LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
| ^ this thread got stuck here
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
= note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
= note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
= note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
note: inside `main`
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
error: the evaluated program deadlocked
|
||||
--> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
--> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
|
|
||||
LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
|
||||
| ^ this thread got stuck here
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
|
||||
= note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
|
||||
= note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
= note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
|
||||
note: inside `main`
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
// FIXME: +soft-float itself doesn't set -vector
|
||||
//@[z13_soft_float] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 -C target-feature=-vector,+soft-float
|
||||
//@[z13_soft_float] needs-llvm-components: systemz
|
||||
//[z13_soft_float]~? WARN must be disabled to ensure that the ABI of the current target can be implemented correctly
|
||||
|
||||
#![feature(no_core, repr_simd, s390x_target_feature)]
|
||||
#![no_core]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:38:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:39:1
|
||||
|
|
||||
LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -7,7 +7,7 @@ LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:43:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:44:1
|
||||
|
|
||||
LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -15,7 +15,7 @@ LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:89:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:90:1
|
||||
|
|
||||
LL | / extern "C" fn vector_transparent_wrapper_ret_small(
|
||||
LL | | x: &TransparentWrapper<i8x8>,
|
||||
|
|
@ -25,7 +25,7 @@ LL | | ) -> TransparentWrapper<i8x8> {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:96:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:97:1
|
||||
|
|
||||
LL | / extern "C" fn vector_transparent_wrapper_ret(
|
||||
LL | | x: &TransparentWrapper<i8x16>,
|
||||
|
|
@ -35,7 +35,7 @@ LL | | ) -> TransparentWrapper<i8x16> {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:111:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:112:1
|
||||
|
|
||||
LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -43,7 +43,7 @@ LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:116:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:117:1
|
||||
|
|
||||
LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -51,7 +51,7 @@ LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `Wrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:127:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:128:1
|
||||
|
|
||||
LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -59,7 +59,7 @@ LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `Wrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:132:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:133:1
|
||||
|
|
||||
LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -67,7 +67,7 @@ LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:143:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:144:1
|
||||
|
|
||||
LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -75,7 +75,7 @@ LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:148:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:149:1
|
||||
|
|
||||
LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:38:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:39:1
|
||||
|
|
||||
LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -7,7 +7,7 @@ LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:43:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:44:1
|
||||
|
|
||||
LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -15,7 +15,7 @@ LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:89:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:90:1
|
||||
|
|
||||
LL | / extern "C" fn vector_transparent_wrapper_ret_small(
|
||||
LL | | x: &TransparentWrapper<i8x8>,
|
||||
|
|
@ -25,7 +25,7 @@ LL | | ) -> TransparentWrapper<i8x8> {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:96:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:97:1
|
||||
|
|
||||
LL | / extern "C" fn vector_transparent_wrapper_ret(
|
||||
LL | | x: &TransparentWrapper<i8x16>,
|
||||
|
|
@ -35,7 +35,7 @@ LL | | ) -> TransparentWrapper<i8x16> {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:111:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:112:1
|
||||
|
|
||||
LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -43,7 +43,7 @@ LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:116:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:117:1
|
||||
|
|
||||
LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -51,7 +51,7 @@ LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `Wrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:127:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:128:1
|
||||
|
|
||||
LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -59,7 +59,7 @@ LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `Wrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:132:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:133:1
|
||||
|
|
||||
LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -67,7 +67,7 @@ LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:143:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:144:1
|
||||
|
|
||||
LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -75,7 +75,7 @@ LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:148:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:149:1
|
||||
|
|
||||
LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
warning: target feature `soft-float` must be disabled to ensure that the ABI of the current target can be implemented correctly
|
||||
|
|
||||
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||
|
||||
error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:38:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:39:1
|
||||
|
|
||||
LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -7,7 +12,7 @@ LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:43:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:44:1
|
||||
|
|
||||
LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -15,7 +20,7 @@ LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:89:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:90:1
|
||||
|
|
||||
LL | / extern "C" fn vector_transparent_wrapper_ret_small(
|
||||
LL | | x: &TransparentWrapper<i8x8>,
|
||||
|
|
@ -25,7 +30,7 @@ LL | | ) -> TransparentWrapper<i8x8> {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:96:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:97:1
|
||||
|
|
||||
LL | / extern "C" fn vector_transparent_wrapper_ret(
|
||||
LL | | x: &TransparentWrapper<i8x16>,
|
||||
|
|
@ -35,7 +40,7 @@ LL | | ) -> TransparentWrapper<i8x16> {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:111:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:112:1
|
||||
|
|
||||
LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -43,7 +48,7 @@ LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:116:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:117:1
|
||||
|
|
||||
LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -51,7 +56,7 @@ LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `Wrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:127:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:128:1
|
||||
|
|
||||
LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -59,7 +64,7 @@ LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `Wrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:132:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:133:1
|
||||
|
|
||||
LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -67,7 +72,7 @@ LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:143:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:144:1
|
||||
|
|
||||
LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -75,12 +80,12 @@ LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8
|
|||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-s390x.rs:148:1
|
||||
--> $DIR/simd-abi-checks-s390x.rs:149:1
|
||||
|
|
||||
LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
||||
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
error: aborting due to 10 previous errors; 1 warning emitted
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,22 @@
|
|||
// Demonstrates and records a theoretical regressions / breaking changes caused by the
|
||||
// introduction of async trait bounds.
|
||||
|
||||
// Setting the edition to 2018 since we don't regress `demo! { dyn async }` in Rust <2018.
|
||||
// Setting the edition to >2015 since we didn't regress `demo! { dyn async }` in Rust 2015.
|
||||
//@ edition:2018
|
||||
|
||||
macro_rules! demo {
|
||||
($ty:ty) => { compile_error!("ty"); };
|
||||
($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!
|
||||
//~^ ERROR ty
|
||||
//~| ERROR ty
|
||||
(impl $c:ident Trait) => {};
|
||||
(dyn $c:ident Trait) => {};
|
||||
|
||||
// DON'T MODIFY THE MATCHERS BELOW UNLESS THE ASYNC TRAIT MODIFIER SYNTAX CHANGES!
|
||||
|
||||
(impl $c:ident Trait) => { /* KEEP THIS EMPTY! */ };
|
||||
(dyn $c:ident Trait) => { /* KEEP THIS EMPTY! */ };
|
||||
}
|
||||
|
||||
demo! { impl async Trait }
|
||||
//~^ ERROR `async` trait bounds are unstable
|
||||
demo! { impl async Trait } //~ ERROR `async` trait bounds are unstable
|
||||
|
||||
demo! { dyn async Trait }
|
||||
//~^ ERROR `async` trait bounds are unstable
|
||||
demo! { dyn async Trait } //~ ERROR `async` trait bounds are unstable
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
error: ty
|
||||
--> $DIR/macro-async-trait-bound-theoretical-regression.rs:8:19
|
||||
|
|
||||
LL | ($ty:ty) => { compile_error!("ty"); };
|
||||
LL | ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | demo! { impl async Trait }
|
||||
|
|
@ -12,7 +12,7 @@ LL | demo! { impl async Trait }
|
|||
error: ty
|
||||
--> $DIR/macro-async-trait-bound-theoretical-regression.rs:8:19
|
||||
|
|
||||
LL | ($ty:ty) => { compile_error!("ty"); };
|
||||
LL | ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | demo! { dyn async Trait }
|
||||
|
|
@ -21,7 +21,7 @@ LL | demo! { dyn async Trait }
|
|||
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0658]: `async` trait bounds are unstable
|
||||
--> $DIR/macro-async-trait-bound-theoretical-regression.rs:15:14
|
||||
--> $DIR/macro-async-trait-bound-theoretical-regression.rs:18:14
|
||||
|
|
||||
LL | demo! { impl async Trait }
|
||||
| ^^^^^
|
||||
|
|
@ -32,7 +32,7 @@ LL | demo! { impl async Trait }
|
|||
= help: use the desugared name of the async trait, such as `AsyncFn`
|
||||
|
||||
error[E0658]: `async` trait bounds are unstable
|
||||
--> $DIR/macro-async-trait-bound-theoretical-regression.rs:18:13
|
||||
--> $DIR/macro-async-trait-bound-theoretical-regression.rs:20:13
|
||||
|
|
||||
LL | demo! { dyn async Trait }
|
||||
| ^^^^^
|
||||
|
|
|
|||
|
|
@ -1,16 +1,4 @@
|
|||
fn main() {
|
||||
assert!("foo"); //~ ERROR mismatched types
|
||||
//~^ NOTE expected `bool`, found `str`
|
||||
//~| NOTE in this expansion of assert!
|
||||
let x = Some(&1);
|
||||
assert!(x); //~ ERROR mismatched types
|
||||
//~^ NOTE expected `bool`, found `Option<&{integer}>`
|
||||
//~| NOTE expected enum `bool`
|
||||
//~| NOTE in this expansion of assert!
|
||||
//~| NOTE in this expansion of assert!
|
||||
assert!(x, ""); //~ ERROR mismatched types
|
||||
//~^ NOTE expected `bool`, found `Option<&{integer}>`
|
||||
//~| NOTE expected enum `bool`
|
||||
//~| NOTE in this expansion of assert!
|
||||
//~| NOTE in this expansion of assert!
|
||||
assert!("foo");
|
||||
//~^ ERROR cannot apply unary operator `!`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,9 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-28308.rs:2:13
|
||||
error[E0600]: cannot apply unary operator `!` to type `&'static str`
|
||||
--> $DIR/issue-28308.rs:2:5
|
||||
|
|
||||
LL | assert!("foo");
|
||||
| ^^^^^ expected `bool`, found `str`
|
||||
| ^^^^^^^^^^^^^^ cannot apply unary operator `!`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-28308.rs:6:13
|
||||
|
|
||||
LL | assert!(x);
|
||||
| ^ expected `bool`, found `Option<&{integer}>`
|
||||
|
|
||||
= note: expected enum `bool`
|
||||
found type `Option<&{integer}>`
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-28308.rs:11:13
|
||||
|
|
||||
LL | assert!(x, "");
|
||||
| ^ expected `bool`, found `Option<&{integer}>`
|
||||
|
|
||||
= note: expected enum `bool`
|
||||
found type `Option<&{integer}>`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
For more information about this error, try `rustc --explain E0600`.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
error[E0080]: evaluation panicked: assertion failed: false
|
||||
--> $DIR/assert.rs:5:23
|
||||
--> $DIR/assert.rs:5:15
|
||||
|
|
||||
LL | const _: () = assert!(false);
|
||||
| ^^^^^ evaluation of `_` failed here
|
||||
| ^^^^^^^^^^^^^^ evaluation of `_` failed here
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
error[E0080]: evaluation panicked: assertion failed: std::mem::size_of::<T>() == 0
|
||||
--> $DIR/post_monomorphization_error_backtrace.rs:6:31
|
||||
--> $DIR/post_monomorphization_error_backtrace.rs:6:23
|
||||
|
|
||||
LL | const V: () = assert!(std::mem::size_of::<T>() == 0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::<u32>::V` failed here
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::<u32>::V` failed here
|
||||
|
||||
note: erroneous constant encountered
|
||||
--> $DIR/post_monomorphization_error_backtrace.rs:14:5
|
||||
|
|
@ -17,10 +17,10 @@ LL | assert_zst::<U>()
|
|||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0080]: evaluation panicked: assertion failed: std::mem::size_of::<T>() == 0
|
||||
--> $DIR/post_monomorphization_error_backtrace.rs:6:31
|
||||
--> $DIR/post_monomorphization_error_backtrace.rs:6:23
|
||||
|
|
||||
LL | const V: () = assert!(std::mem::size_of::<T>() == 0);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::<i32>::V` failed here
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `assert_zst::F::<i32>::V` failed here
|
||||
|
||||
note: erroneous constant encountered
|
||||
--> $DIR/post_monomorphization_error_backtrace.rs:14:5
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
error[E0080]: evaluation panicked: assertion failed: std::mem::size_of::<T>() == 0
|
||||
--> $DIR/const-expr-generic-err.rs:4:21
|
||||
--> $DIR/const-expr-generic-err.rs:4:13
|
||||
|
|
||||
LL | const { assert!(std::mem::size_of::<T>() == 0); }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `foo::<i32>::{constant#0}` failed here
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `foo::<i32>::{constant#0}` failed here
|
||||
|
||||
note: erroneous constant encountered
|
||||
--> $DIR/const-expr-generic-err.rs:4:5
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@
|
|||
//@ [strict]compile-flags: -Zstrict-init-checks
|
||||
//@ needs-subprocess
|
||||
//@ ignore-backends: gcc
|
||||
//@ edition:2024
|
||||
|
||||
#![allow(deprecated, invalid_value)]
|
||||
#![feature(never_type)]
|
||||
#![feature(never_type, rustc_private)]
|
||||
|
||||
use std::{
|
||||
mem::{self, MaybeUninit, ManuallyDrop},
|
||||
|
|
@ -15,6 +16,9 @@ use std::{
|
|||
num,
|
||||
};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
extern crate libc;
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct Foo {
|
||||
x: u8,
|
||||
|
|
@ -108,6 +112,17 @@ fn test_panic_msg_only_if_strict<T>(op: impl (FnOnce() -> T) + 'static, msg: &st
|
|||
|
||||
fn main() {
|
||||
unsafe {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
// This test causes a large amount of crashes. If a system
|
||||
// has a /proc/sys/kernel/core_pattern that uploads core dumps enabled,
|
||||
// it will take a long time to complete. Set dumpable to 0 to avoid that.
|
||||
if libc::prctl(libc::PR_SET_DUMPABLE, 0) < 0 {
|
||||
let err = std::io::Error::last_os_error();
|
||||
panic!("failed to disable core dumps {err:?}");
|
||||
}
|
||||
}
|
||||
|
||||
// Uninhabited types
|
||||
test_panic_msg(
|
||||
|| mem::uninitialized::<!>(),
|
||||
|
|
|
|||
23
tests/ui/macros/assert-desugaring-145770.rs
Normal file
23
tests/ui/macros/assert-desugaring-145770.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
//! Regression test for #145770.
|
||||
//!
|
||||
//! Changing the `assert!` desugaring from an `if !cond {}` to `match` expression is
|
||||
//! backwards-incompatible, and may need to be done over an edition boundary or limit editions for
|
||||
//! which the desguaring change impacts.
|
||||
|
||||
//@ check-pass
|
||||
|
||||
#[derive(Debug)]
|
||||
struct F {
|
||||
data: bool
|
||||
}
|
||||
|
||||
impl std::ops::Not for F {
|
||||
type Output = bool;
|
||||
fn not(self) -> Self::Output { !self.data }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let f = F { data: true };
|
||||
|
||||
assert!(f);
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
//@ check-pass
|
||||
#[derive(PartialEq, Eq, Hash)]
|
||||
struct S;
|
||||
fn main() {
|
||||
let foo = std::rc::Rc::new(std::cell::RefCell::new(std::collections::HashMap::<S, S>::new()));
|
||||
// Ensure that the lifetimes of the borrow do not leak past the end of `main`.
|
||||
assert!(matches!(foo.borrow().get(&S).unwrap(), S))
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@ fn main() {
|
|||
// Test that we can use addr_of! to get the address of a packed member which according to its
|
||||
// type is not aligned, but because it is a projection from a packed type is a valid place.
|
||||
let ptr0 = std::ptr::addr_of!(memory[0].tail);
|
||||
let ptr1 = std::ptr::addr_of!(memory[1].tail);
|
||||
let ptr1 = std::ptr::addr_of!(memory[0].tail);
|
||||
// Even if ptr0 happens to be aligned by chance, ptr1 is not.
|
||||
assert!(!ptr0.is_aligned() || !ptr1.is_aligned());
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
error[E0080]: evaluation panicked: assertion failed: LANE < 4
|
||||
--> $DIR/const-err-trumps-simd-err.rs:17:21
|
||||
--> $DIR/const-err-trumps-simd-err.rs:17:13
|
||||
|
|
||||
LL | const { assert!(LANE < 4); } // the error should be here...
|
||||
| ^^^^^^^^ evaluation of `get_elem::<4>::{constant#0}` failed here
|
||||
| ^^^^^^^^^^^^^^^^^ evaluation of `get_elem::<4>::{constant#0}` failed here
|
||||
|
||||
note: erroneous constant encountered
|
||||
--> $DIR/const-err-trumps-simd-err.rs:17:5
|
||||
|
|
|
|||
|
|
@ -1,24 +1,23 @@
|
|||
// Ensure that we don't consider `const Trait` to
|
||||
// match the macro fragment specifier `ty` as that would be a breaking
|
||||
// change theoretically speaking. Syntactically trait object types can
|
||||
// be "bare", i.e., lack the prefix `dyn`.
|
||||
// By contrast, `?Trait` *does* match `ty` and therefore an arm like
|
||||
// `?$Trait:path` would never be reached.
|
||||
// See `parser/macro/mbe-bare-trait-object-maybe-trait-bound.rs`.
|
||||
// `[const] Trait` is already an error for a `ty` fragment,
|
||||
// so we do not need to prevent that.
|
||||
// Ensure that we don't consider `const Trait` to match the macro fragment specifier `ty`
|
||||
// as that would be a breaking change theoretically speaking.
|
||||
//
|
||||
// Syntactically trait object types can be "bare", i.e., lack the prefix `dyn`.
|
||||
// By contrast, `?Trait` *does* match `ty` and therefore an arm like `?$Trait:path`
|
||||
// would never be reached. See `parser/macro/macro-bare-trait-object-maybe-trait-bound.rs`.
|
||||
|
||||
//@ check-pass (KEEP THIS AS A PASSING TEST!)
|
||||
|
||||
macro_rules! check {
|
||||
($Type:ty) => {
|
||||
compile_error!("ty");
|
||||
};
|
||||
(const $Trait:path) => {};
|
||||
([const] $Trait:path) => { [const] Trait };
|
||||
($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!
|
||||
|
||||
// DON'T MODIFY THE MATCHERS BELOW UNLESS THE CONST TRAIT MODIFIER SYNTAX CHANGES!
|
||||
|
||||
(const $Trait:path) => { /* KEEP THIS EMPTY! */ };
|
||||
// We don't need to check `[const] Trait` here since that matches the `ty` fragment
|
||||
// already anyway since `[` may begin a slice or array type. However, it'll then
|
||||
// subsequently fail due to #146122 (section 3).
|
||||
}
|
||||
|
||||
check! { const Trait }
|
||||
check! { [const] Trait }
|
||||
//~^ ERROR: expected identifier, found `]`
|
||||
//~| ERROR: const trait impls are experimental
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
error: expected identifier, found `]`
|
||||
--> $DIR/macro-bare-trait-objects-const-trait-bounds.rs:20:16
|
||||
|
|
||||
LL | ($Type:ty) => {
|
||||
| -------- while parsing argument for this `ty` macro fragment
|
||||
...
|
||||
LL | check! { [const] Trait }
|
||||
| ^ expected identifier
|
||||
|
||||
error[E0658]: const trait impls are experimental
|
||||
--> $DIR/macro-bare-trait-objects-const-trait-bounds.rs:20:11
|
||||
|
|
||||
LL | check! { [const] Trait }
|
||||
| ^^^^^
|
||||
|
|
||||
= note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information
|
||||
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
|
@ -1,22 +1,32 @@
|
|||
// Demonstrates and records a theoretical regressions / breaking changes caused by the
|
||||
// introduction of const trait bounds.
|
||||
// introduction of `const` and `[const]` trait bounds.
|
||||
|
||||
// Setting the edition to 2018 since we don't regress `demo! { dyn const }` in Rust <2018.
|
||||
// Setting the edition to >2015 since we didn't regress `demo! { dyn const }` in Rust 2015.
|
||||
// See also test `traits/const-traits/macro-dyn-const-2015.rs`.
|
||||
//@ edition:2018
|
||||
|
||||
trait Trait {}
|
||||
|
||||
macro_rules! demo {
|
||||
(impl $c:ident Trait) => { impl $c Trait {} };
|
||||
//~^ ERROR inherent
|
||||
//~| WARN trait objects without an explicit `dyn` are deprecated
|
||||
//~| WARN this is accepted in the current edition
|
||||
(dyn $c:ident Trait) => { dyn $c Trait {} }; //~ ERROR macro expansion
|
||||
($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!
|
||||
//~^ ERROR ty
|
||||
//~| ERROR ty
|
||||
//~| ERROR ty
|
||||
//~| ERROR ty
|
||||
|
||||
// DON'T MODIFY THE MATCHERS BELOW UNLESS THE CONST TRAIT MODIFIER SYNTAX CHANGES!
|
||||
|
||||
(impl $c:ident Trait) => { /* KEEP THIS EMPTY! */ };
|
||||
(dyn $c:ident Trait) => { /* KEEP THIS EMPTY! */ };
|
||||
|
||||
(impl [const] Trait) => { /* KEEP THIS EMPTY! */ };
|
||||
(dyn [const] Trait) => { /* KEEP THIS EMPTY! */ };
|
||||
}
|
||||
|
||||
demo! { impl const Trait }
|
||||
//~^ ERROR const trait impls are experimental
|
||||
demo! { impl const Trait } //~ ERROR const trait impls are experimental
|
||||
demo! { dyn const Trait } //~ ERROR const trait impls are experimental
|
||||
|
||||
demo! { dyn const Trait }
|
||||
demo! { impl [const] Trait } //~ ERROR const trait impls are experimental
|
||||
demo! { dyn [const] Trait } //~ ERROR const trait impls are experimental
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,31 +1,49 @@
|
|||
error: inherent impls cannot be const
|
||||
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:10:40
|
||||
error: ty
|
||||
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:11:19
|
||||
|
|
||||
LL | (impl $c:ident Trait) => { impl $c Trait {} };
|
||||
| ^^^^^ inherent impl for this type
|
||||
LL | ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | demo! { impl const Trait }
|
||||
| --------------------------
|
||||
| | |
|
||||
| | const because of this
|
||||
| in this macro invocation
|
||||
| -------------------------- in this macro invocation
|
||||
|
|
||||
= note: only trait implementations may be annotated with `const`
|
||||
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: macro expansion ignores keyword `dyn` and any tokens following
|
||||
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:14:31
|
||||
error: ty
|
||||
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:11:19
|
||||
|
|
||||
LL | (dyn $c:ident Trait) => { dyn $c Trait {} };
|
||||
| ^^^
|
||||
LL | ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | demo! { dyn const Trait }
|
||||
| ------------------------- caused by the macro expansion here
|
||||
| ------------------------- in this macro invocation
|
||||
|
|
||||
= note: the usage of `demo!` is likely invalid in item context
|
||||
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: ty
|
||||
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:11:19
|
||||
|
|
||||
LL | ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | demo! { impl [const] Trait }
|
||||
| ---------------------------- in this macro invocation
|
||||
|
|
||||
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: ty
|
||||
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:11:19
|
||||
|
|
||||
LL | ($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | demo! { dyn [const] Trait }
|
||||
| --------------------------- in this macro invocation
|
||||
|
|
||||
= note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0658]: const trait impls are experimental
|
||||
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:17:14
|
||||
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:26:14
|
||||
|
|
||||
LL | demo! { impl const Trait }
|
||||
| ^^^^^
|
||||
|
|
@ -34,24 +52,36 @@ LL | demo! { impl const Trait }
|
|||
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
warning: trait objects without an explicit `dyn` are deprecated
|
||||
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:10:40
|
||||
error[E0658]: const trait impls are experimental
|
||||
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:27:13
|
||||
|
|
||||
LL | (impl $c:ident Trait) => { impl $c Trait {} };
|
||||
| ^^^^^
|
||||
...
|
||||
LL | demo! { impl const Trait }
|
||||
| -------------------------- in this macro invocation
|
||||
LL | demo! { dyn const Trait }
|
||||
| ^^^^^
|
||||
|
|
||||
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
|
||||
= note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/warnings-promoted-to-error.html>
|
||||
= note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default
|
||||
= note: this warning originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: you might have intended to implement this trait for a given type
|
||||
|
|
||||
LL | (impl $c:ident Trait) => { impl $c Trait for /* Type */ {} };
|
||||
| ++++++++++++++
|
||||
= note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information
|
||||
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 3 previous errors; 1 warning emitted
|
||||
error[E0658]: const trait impls are experimental
|
||||
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:29:14
|
||||
|
|
||||
LL | demo! { impl [const] Trait }
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information
|
||||
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: const trait impls are experimental
|
||||
--> $DIR/macro-const-trait-bound-theoretical-regression.rs:30:13
|
||||
|
|
||||
LL | demo! { dyn [const] Trait }
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information
|
||||
= help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
|
|
|||
|
|
@ -1,14 +1,19 @@
|
|||
// Ensure that the introduction of const trait bound didn't regress this code in Rust 2015.
|
||||
// See also `mbe-const-trait-bound-theoretical-regression.rs`.
|
||||
// Ensure that the introduction of `const` and `[const]` trait bounds didn't regress this
|
||||
// Rust 2015 code. See also test `macro-const-trait-bound-theoretical-regression.rs`.
|
||||
|
||||
//@ edition: 2015
|
||||
//@ check-pass
|
||||
//@ check-pass (KEEP THIS AS A PASSING TEST!)
|
||||
|
||||
macro_rules! check {
|
||||
($ty:ty) => { compile_error!("ty"); };
|
||||
(dyn $c:ident) => {};
|
||||
($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!
|
||||
|
||||
// DON'T MODIFY THE MATCHERS BELOW UNLESS THE CONST TRAIT MODIFIER SYNTAX CHANGES!
|
||||
|
||||
(dyn $c:ident) => { /* KEEP THIS EMPTY! */ };
|
||||
(dyn [$c:ident]) => { /* KEEP THIS EMPTY! */ };
|
||||
}
|
||||
|
||||
check! { dyn const }
|
||||
check! { dyn [const] }
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
// Ensure that we don't consider `[` to begin trait bounds to contain breakages.
|
||||
// Only `[const]` in its entirety begins a trait bound.
|
||||
// See also test `macro-const-trait-bound-theoretical-regression.rs`.
|
||||
|
||||
//@ check-pass (KEEP THIS AS A PASSING TEST!)
|
||||
// Setting the edition to >2015 since we didn't regress `check! { dyn [const] Trait }` in Rust 2015.
|
||||
// See also test `traits/const-traits/macro-dyn-const-2015.rs`.
|
||||
//@ edition:2018
|
||||
|
||||
macro_rules! check {
|
||||
($ty:ty) => { compile_error!("ty"); }; // KEEP THIS RULE FIRST AND AS IS!
|
||||
|
||||
// DON'T MODIFY THE MATCHERS BELOW UNLESS THE CONST TRAIT MODIFIER SYNTAX CHANGES!
|
||||
|
||||
(dyn [$($any:tt)*] Trait) => { /* KEEP THIS EMPTY! */ };
|
||||
(impl [$($any:tt)*] Trait) => { /* KEEP THIS EMPTY! */ };
|
||||
}
|
||||
|
||||
check!(dyn [T] Trait);
|
||||
|
||||
// issue: <https://github.com/rust-lang/rust/issues/146417>
|
||||
check!(impl [T] Trait);
|
||||
check!(impl [T: Bound] Trait);
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -41,10 +41,10 @@ LL | | }>
|
|||
| |__________^ required by this bound in `is_maybe_transmutable`
|
||||
|
||||
error[E0080]: evaluation panicked: assertion failed: false
|
||||
--> $DIR/uninhabited.rs:41:17
|
||||
--> $DIR/uninhabited.rs:41:9
|
||||
|
|
||||
LL | assert!(false);
|
||||
| ^^^^^ evaluation of `yawning_void_struct::_` failed here
|
||||
| ^^^^^^^^^^^^^^ evaluation of `yawning_void_struct::_` failed here
|
||||
|
||||
error[E0277]: `()` cannot be safely transmuted into `yawning_void_enum::Void`
|
||||
--> $DIR/uninhabited.rs:71:41
|
||||
|
|
@ -68,10 +68,10 @@ LL | | }>
|
|||
| |__________^ required by this bound in `is_maybe_transmutable`
|
||||
|
||||
error[E0080]: evaluation panicked: assertion failed: false
|
||||
--> $DIR/uninhabited.rs:63:17
|
||||
--> $DIR/uninhabited.rs:63:9
|
||||
|
|
||||
LL | assert!(false);
|
||||
| ^^^^^ evaluation of `yawning_void_enum::_` failed here
|
||||
| ^^^^^^^^^^^^^^ evaluation of `yawning_void_enum::_` failed here
|
||||
|
||||
error[E0277]: `u128` cannot be safely transmuted into `DistantVoid`
|
||||
--> $DIR/uninhabited.rs:92:43
|
||||
|
|
@ -95,10 +95,10 @@ LL | | }>
|
|||
| |__________^ required by this bound in `is_maybe_transmutable`
|
||||
|
||||
error[E0080]: evaluation panicked: assertion failed: false
|
||||
--> $DIR/uninhabited.rs:87:17
|
||||
--> $DIR/uninhabited.rs:87:9
|
||||
|
|
||||
LL | assert!(false);
|
||||
| ^^^^^ evaluation of `distant_void::_` failed here
|
||||
| ^^^^^^^^^^^^^^ evaluation of `distant_void::_` failed here
|
||||
|
||||
error[E0277]: `Src` cannot be safely transmuted into `issue_126267::Error`
|
||||
--> $DIR/uninhabited.rs:108:42
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue