Merge ref '2a9bacf618' from rust-lang/rust

Pull recent changes from https://github.com/rust-lang/rust via Josh.

Upstream ref: 2a9bacf618
Filtered ref: d7fc6d06166167894862d54c9618a3cd7599fa9c
Upstream diff: f4665ab836...2a9bacf618

This merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
The Miri Cronjob Bot 2025-09-12 05:00:07 +00:00
commit 7bc4a3be4c
96 changed files with 1503 additions and 1661 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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.

View 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.

View 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.

View 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.

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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!("{:?}", ..), "..");
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View 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;
}
}

View file

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

View file

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

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

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

View 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;
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -196,7 +196,6 @@ fn issue_13106() {
const {
assert!(EMPTY_STR.is_empty());
//~^ const_is_empty
}
const {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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() {}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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::<!>(),

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

View file

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

View file

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

View file

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

View file

@ -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() {}

View file

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

View file

@ -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() {}

View file

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

View file

@ -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() {}

View file

@ -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() {}

View file

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