Auto merge of #146526 - jhpratt:rollup-afb1dgo, r=jhpratt

Rollup of 8 pull requests

Successful merges:

 - rust-lang/rust#113095 (Document `become` keyword)
 - rust-lang/rust#146159 (Some hygiene doc improvements)
 - rust-lang/rust#146171 (tidy: check that error messages don't start with a capitalized letter)
 - rust-lang/rust#146419 (Update the arm-* and aarch64-* platform docs.)
 - rust-lang/rust#146473 (Revert "Constify SystemTime methods")
 - rust-lang/rust#146506 (Fix small typo in check-cfg.md)
 - rust-lang/rust#146517 (fix Condvar::wait_timeout docs)
 - rust-lang/rust#146521 (document `core::ffi::VaArgSafe`)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-09-13 23:02:12 +00:00
commit a015919e54
45 changed files with 673 additions and 255 deletions

View file

@ -31,7 +31,7 @@ codegen_ssa_cpu_required = target requires explicitly specifying a cpu with `-C
codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
codegen_ssa_dlltool_fail_import_library =
Dlltool could not create import library with {$dlltool_path} {$dlltool_args}:
dlltool could not create import library with {$dlltool_path} {$dlltool_args}:
{$stdout}
{$stderr}

View file

@ -75,7 +75,7 @@ passes_const_stable_not_stable =
.label = attribute specified here
passes_custom_mir_incompatible_dialect_and_phase =
The {$dialect} dialect is not compatible with the {$phase} phase
the {$dialect} dialect is not compatible with the {$phase} phase
.dialect_span = this dialect...
.phase_span = ... is not compatible with this phase

View file

@ -46,6 +46,8 @@ use crate::symbol::{Symbol, kw, sym};
use crate::{DUMMY_SP, HashStableContext, Span, SpanDecoder, SpanEncoder, with_session_globals};
/// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks".
///
/// See <https://rustc-dev-guide.rust-lang.org/macro-expansion.html> for more explanation.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct SyntaxContext(u32);
@ -61,7 +63,10 @@ pub type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency);
#[derive(Clone, Copy, Debug)]
struct SyntaxContextData {
/// The last macro expansion in the chain.
/// (Here we say the most deeply nested macro expansion is the "outermost" expansion.)
outer_expn: ExpnId,
/// Transparency of the last macro expansion
outer_transparency: Transparency,
parent: SyntaxContext,
/// This context, but with all transparent and semi-opaque expansions filtered away.
@ -450,11 +455,13 @@ impl HygieneData {
self.syntax_context_data[ctxt.0 as usize].opaque_and_semiopaque
}
/// See [`SyntaxContextData::outer_expn`]
#[inline]
fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId {
self.syntax_context_data[ctxt.0 as usize].outer_expn
}
/// The last macro expansion and its Transparency
#[inline]
fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) {
let data = &self.syntax_context_data[ctxt.0 as usize];
@ -900,6 +907,7 @@ impl SyntaxContext {
HygieneData::with(|data| data.normalize_to_macro_rules(self))
}
/// See [`SyntaxContextData::outer_expn`]
#[inline]
pub fn outer_expn(self) -> ExpnId {
HygieneData::with(|data| data.outer_expn(self))
@ -912,6 +920,7 @@ impl SyntaxContext {
HygieneData::with(|data| data.expn_data(data.outer_expn(self)).clone())
}
/// See [`HygieneData::outer_mark`]
#[inline]
fn outer_mark(self) -> (ExpnId, Transparency) {
HygieneData::with(|data| data.outer_mark(self))
@ -982,19 +991,20 @@ impl Span {
#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)]
pub struct ExpnData {
// --- The part unique to each expansion.
/// The kind of this expansion - macro or compiler desugaring.
pub kind: ExpnKind,
/// The expansion that produced this expansion.
/// The expansion that contains the definition of the macro for this expansion.
pub parent: ExpnId,
/// The location of the actual macro invocation or syntax sugar , e.g.
/// `let x = foo!();` or `if let Some(y) = x {}`
/// The span of the macro call which produced this expansion.
///
/// This may recursively refer to other macro invocations, e.g., if
/// `foo!()` invoked `bar!()` internally, and there was an
/// expression inside `bar!`; the call_site of the expression in
/// the expansion would point to the `bar!` invocation; that
/// call_site span would have its own ExpnData, with the call_site
/// pointing to the `foo!` invocation.
/// This span will typically have a different `ExpnData` and `call_site`.
/// This recursively traces back through any macro calls which expanded into further
/// macro calls, until the "source call-site" is reached at the root SyntaxContext.
/// For example, if `food!()` expands to `fruit!()` which then expands to `grape`,
/// then the call-site of `grape` is `fruit!()` and the call-site of `fruit!()`
/// is `food!()`.
///
/// For a desugaring expansion, this is the span of the expression or node that was
/// desugared.
pub call_site: Span,
/// Used to force two `ExpnData`s to have different `Fingerprint`s.
/// Due to macro expansion, it's possible to end up with two `ExpnId`s

View file

@ -710,8 +710,8 @@ impl Span {
if !ctxt.is_root() { ctxt.outer_expn_data().call_site.source_callsite() } else { self }
}
/// The `Span` for the tokens in the previous macro expansion from which `self` was generated,
/// if any.
/// Returns the call-site span of the last macro expansion which produced this `Span`.
/// (see [`ExpnData::call_site`]). Returns `None` if this is not an expansion.
pub fn parent_callsite(self) -> Option<Span> {
let ctxt = self.ctxt();
(!ctxt.is_root()).then(|| ctxt.outer_expn_data().call_site)

View file

@ -202,18 +202,23 @@ mod sealed {
impl<T> Sealed for *const T {}
}
/// Trait which permits the allowed types to be used with [`VaListImpl::arg`].
/// Types that are valid to read using [`VaListImpl::arg`].
///
/// # Safety
///
/// This trait must only be implemented for types that C passes as varargs without implicit promotion.
/// The standard library implements this trait for primitive types that are
/// expected to have a variable argument application-binary interface (ABI) on all
/// platforms.
///
/// In C varargs, integers smaller than [`c_int`] and floats smaller than [`c_double`]
/// are implicitly promoted to [`c_int`] and [`c_double`] respectively. Implementing this trait for
/// types that are subject to this promotion rule is invalid.
/// When C passes variable arguments, integers smaller than [`c_int`] and floats smaller
/// than [`c_double`] are implicitly promoted to [`c_int`] and [`c_double`] respectively.
/// Implementing this trait for types that are subject to this promotion rule is invalid.
///
/// [`c_int`]: core::ffi::c_int
/// [`c_double`]: core::ffi::c_double
// We may unseal this trait in the future, but currently our `va_arg` implementations don't support
// types with an alignment larger than 8, or with a non-scalar layout. Inline assembly can be used
// to accept unsupported types in the meantime.
pub unsafe trait VaArgSafe: sealed::Sealed {}
// i8 and i16 are implicitly promoted to c_int in C, and cannot implement `VaArgSafe`.
@ -233,7 +238,19 @@ unsafe impl<T> VaArgSafe for *mut T {}
unsafe impl<T> VaArgSafe for *const T {}
impl<'f> VaListImpl<'f> {
/// Advance to the next arg.
/// Advance to and read the next variable argument.
///
/// # Safety
///
/// This function is only sound to call when the next variable argument:
///
/// - has a type that is ABI-compatible with the type `T`
/// - has a value that is a properly initialized value of type `T`
///
/// Calling this function with an incompatible type, an invalid value, or when there
/// are no more variable arguments, is unsound.
///
/// [valid]: https://doc.rust-lang.org/nightly/nomicon/what-unsafe-does.html
#[inline]
pub unsafe fn arg<T: VaArgSafe>(&mut self) -> T {
// SAFETY: the caller must uphold the safety contract for `va_arg`.

View file

@ -1257,6 +1257,108 @@ mod ref_keyword {}
/// [`async`]: ../std/keyword.async.html
mod return_keyword {}
#[doc(keyword = "become")]
//
/// Perform a tail-call of a function.
///
/// <div class="warning">
///
/// `feature(explicit_tail_calls)` is currently incomplete and may not work properly.
/// </div>
///
/// When tail calling a function, instead of its stack frame being added to the
/// stack, the stack frame of the caller is directly replaced with the callee's.
/// This means that as long as a loop in a call graph only uses tail calls, the
/// stack growth will be bounded.
///
/// This is useful for writing functional-style code (since it prevents recursion
/// from exhausting resources) or for code optimization (since a tail call
/// *might* be cheaper than a normal call, tail calls can be used in a similar
/// manner to computed goto).
///
/// Example of using `become` to implement functional-style `fold`:
/// ```
/// #![feature(explicit_tail_calls)]
/// #![expect(incomplete_features)]
///
/// fn fold<T: Copy, S>(slice: &[T], init: S, f: impl Fn(S, T) -> S) -> S {
/// match slice {
/// // without `become`, on big inputs this could easily overflow the
/// // stack. using a tail call guarantees that the stack will not grow unboundedly
/// [first, rest @ ..] => become fold(rest, f(init, *first), f),
/// [] => init,
/// }
/// }
/// ```
///
/// Compilers can already perform "tail call optimization" -- they can replace normal
/// calls with tail calls, although there are no guarantees that this will be done.
/// However, to perform TCO, the call needs to be the last thing that happens
/// in the functions and be returned from it. This requirement is often broken
/// by drop code for locals, which is run after computing the return expression:
///
/// ```
/// fn example() {
/// let string = "meow".to_owned();
/// println!("{string}");
/// return help(); // this is *not* the last thing that happens in `example`...
/// }
///
/// // ... because it is desugared to this:
/// fn example_desugared() {
/// let string = "meow".to_owned();
/// println!("{string}");
/// let tmp = help();
/// drop(string);
/// return tmp;
/// }
///
/// fn help() {}
/// ```
///
/// For this reason, `become` also changes the drop order, such that locals are
/// dropped *before* evaluating the call.
///
/// In order to guarantee that the compiler can perform a tail call, `become`
/// currently has these requirements:
/// 1. callee and caller must have the same ABI, arguments, and return type
/// 2. callee and caller must not have varargs
/// 3. caller must not be marked with `#[track_caller]`
/// - callee is allowed to be marked with `#[track_caller]` as otherwise
/// adding `#[track_caller]` would be a breaking change. if callee is
/// marked with `#[track_caller]` a tail call is not guaranteed.
/// 4. callee and caller cannot be a closure
/// (unless it's coerced to a function pointer)
///
/// It is possible to tail-call a function pointer:
/// ```
/// #![feature(explicit_tail_calls)]
/// #![expect(incomplete_features)]
///
/// #[derive(Copy, Clone)]
/// enum Inst { Inc, Dec }
///
/// fn dispatch(stream: &[Inst], state: u32) -> u32 {
/// const TABLE: &[fn(&[Inst], u32) -> u32] = &[increment, decrement];
/// match stream {
/// [inst, rest @ ..] => become TABLE[*inst as usize](rest, state),
/// [] => state,
/// }
/// }
///
/// fn increment(stream: &[Inst], state: u32) -> u32 {
/// become dispatch(stream, state + 1)
/// }
///
/// fn decrement(stream: &[Inst], state: u32) -> u32 {
/// become dispatch(stream, state - 1)
/// }
///
/// let program = &[Inst::Inc, Inst::Inc, Inst::Dec, Inst::Inc];
/// assert_eq!(dispatch(program, 0), 2);
/// ```
mod become_keyword {}
#[doc(keyword = "self")]
//
/// The receiver of a method, or the current module.

View file

@ -284,7 +284,6 @@
#![feature(core_float_math)]
#![feature(decl_macro)]
#![feature(deprecated_suggestion)]
#![feature(derive_const)]
#![feature(doc_cfg)]
#![feature(doc_cfg_hide)]
#![feature(doc_masked)]
@ -332,11 +331,7 @@
#![feature(cfg_select)]
#![feature(char_internals)]
#![feature(clone_to_uninit)]
#![feature(const_cmp)]
#![feature(const_convert)]
#![feature(const_ops)]
#![feature(const_option_ops)]
#![feature(const_try)]
#![feature(core_intrinsics)]
#![feature(core_io_borrowed_buf)]
#![feature(drop_guard)]

View file

@ -198,11 +198,10 @@ impl Condvar {
/// the system time. This function is susceptible to spurious wakeups.
/// Condition variables normally have a boolean predicate associated with
/// them, and the predicate must always be checked each time this function
/// returns to protect against spurious wakeups. Additionally, it is
/// typically desirable for the timeout to not exceed some duration in
/// spite of spurious wakes, thus the sleep-duration is decremented by the
/// amount slept. Alternatively, use the `wait_timeout_while` method
/// to wait with a timeout while a predicate is true.
/// returns to protect against spurious wakeups. Furthermore, since the timeout
/// is given relative to the moment this function is called, it needs to be adjusted
/// when this function is called in a loop. The [`wait_timeout_while`] method
/// lets you wait with a timeout while a predicate is true, taking care of all these concerns.
///
/// The returned [`WaitTimeoutResult`] value indicates if the timeout is
/// known to have elapsed.

View file

@ -269,11 +269,10 @@ impl Condvar {
/// the system time. This function is susceptible to spurious wakeups.
/// Condition variables normally have a boolean predicate associated with
/// them, and the predicate must always be checked each time this function
/// returns to protect against spurious wakeups. Additionally, it is
/// typically desirable for the timeout to not exceed some duration in
/// spite of spurious wakes, thus the sleep-duration is decremented by the
/// amount slept. Alternatively, use the `wait_timeout_while` method
/// to wait with a timeout while a predicate is true.
/// returns to protect against spurious wakeups. Furthermore, since the timeout
/// is given relative to the moment this function is called, it needs to be adjusted
/// when this function is called in a loop. The [`wait_timeout_while`] method
/// lets you wait with a timeout while a predicate is true, taking care of all these concerns.
///
/// The returned [`WaitTimeoutResult`] value indicates if the timeout is
/// known to have elapsed.

View file

@ -25,15 +25,8 @@ impl Timespec {
Timespec { t: timespec { tv_sec, tv_nsec } }
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
const fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
// FIXME: const PartialOrd
let mut cmp = self.t.tv_sec - other.t.tv_sec;
if cmp == 0 {
cmp = self.t.tv_nsec as i64 - other.t.tv_nsec as i64;
}
if cmp >= 0 {
fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
if self >= other {
Ok(if self.t.tv_nsec >= other.t.tv_nsec {
Duration::new(
(self.t.tv_sec - other.t.tv_sec) as u64,
@ -53,22 +46,20 @@ impl Timespec {
}
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
const fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = self.t.tv_sec.checked_add_unsigned(other.as_secs())?;
// Nano calculations can't overflow because nanos are <1B which fit
// in a u32.
let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
if nsec >= NSEC_PER_SEC as u32 {
nsec -= NSEC_PER_SEC as u32;
let mut nsec = other.subsec_nanos() + u32::try_from(self.t.tv_nsec).unwrap();
if nsec >= NSEC_PER_SEC.try_into().unwrap() {
nsec -= u32::try_from(NSEC_PER_SEC).unwrap();
secs = secs.checked_add(1)?;
}
Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } })
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
const fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = self.t.tv_sec.checked_sub_unsigned(other.as_secs())?;
// Similar to above, nanos can't overflow.
@ -222,18 +213,15 @@ impl SystemTime {
SystemTime(time)
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.0.sub_timespec(&other.0)
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_add_duration(other)?))
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_sub_duration(other)?))
}
}

View file

@ -32,22 +32,15 @@ impl SystemTime {
SystemTime(usercalls::insecure_time())
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
// FIXME: ok_or_else with const closures
match self.0.checked_sub(other.0) {
Some(duration) => Ok(duration),
None => Err(other.0 - self.0),
}
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_add(*other)?))
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_sub(*other)?))
}
}

View file

@ -39,8 +39,7 @@ impl SystemTime {
Self(t)
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
if self.0 >= other.0 {
Ok(Duration::from_secs((self.0 as u64).wrapping_sub(other.0 as u64)))
} else {
@ -48,13 +47,11 @@ impl SystemTime {
}
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_add_unsigned(other.as_secs())?))
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_sub_unsigned(other.as_secs())?))
}
}

View file

@ -80,32 +80,19 @@ impl SystemTime {
.unwrap_or_else(|| panic!("time not implemented on this platform"))
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
// FIXME: ok_or_else with const closures
match self.0.checked_sub(other.0) {
Some(duration) => Ok(duration),
None => Err(other.0 - self.0),
}
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
let temp = self.0.checked_add(*other)?;
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
let temp = Self(self.0.checked_add(*other)?);
// Check if can be represented in UEFI
// FIXME: const PartialOrd
let mut cmp = temp.as_secs() - MAX_UEFI_TIME.0.as_secs();
if cmp == 0 {
cmp = temp.subsec_nanos() as u64 - MAX_UEFI_TIME.0.subsec_nanos() as u64;
}
if cmp <= 0 { Some(SystemTime(temp)) } else { None }
if temp <= MAX_UEFI_TIME { Some(temp) } else { None }
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_sub(*other)?))
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
self.0.checked_sub(*other).map(Self)
}
}

View file

@ -38,18 +38,15 @@ impl SystemTime {
SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.t.sub_timespec(&other.t)
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime { t: self.t.checked_add_duration(other)? })
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime { t: self.t.checked_sub_duration(other)? })
}
}
@ -136,15 +133,8 @@ impl Timespec {
Timespec::new(t.tv_sec as i64, t.tv_nsec as i64).unwrap()
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
// FIXME: const PartialOrd
let mut cmp = self.tv_sec - other.tv_sec;
if cmp == 0 {
cmp = self.tv_nsec.as_inner() as i64 - other.tv_nsec.as_inner() as i64;
}
if cmp >= 0 {
pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
if self >= other {
// NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
// to optimize it into a branchless form (see also #75545):
//
@ -179,8 +169,7 @@ impl Timespec {
}
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
pub fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = self.tv_sec.checked_add_unsigned(other.as_secs())?;
// Nano calculations can't overflow because nanos are <1B which fit
@ -190,11 +179,10 @@ impl Timespec {
nsec -= NSEC_PER_SEC as u32;
secs = secs.checked_add(1)?;
}
Some(unsafe { Timespec::new_unchecked(secs, nsec as i64) })
Some(unsafe { Timespec::new_unchecked(secs, nsec.into()) })
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
let mut secs = self.tv_sec.checked_sub_unsigned(other.as_secs())?;
// Similar to above, nanos can't overflow.
@ -203,7 +191,7 @@ impl Timespec {
nsec += NSEC_PER_SEC as i32;
secs = secs.checked_sub(1)?;
}
Some(unsafe { Timespec::new_unchecked(secs, nsec as i64) })
Some(unsafe { Timespec::new_unchecked(secs, nsec.into()) })
}
#[allow(dead_code)]

View file

@ -31,22 +31,15 @@ impl SystemTime {
panic!("time not implemented on this platform")
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
// FIXME: ok_or_else with const closures
match self.0.checked_sub(other.0) {
Some(duration) => Ok(duration),
None => Err(other.0 - self.0),
}
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_add(*other)?))
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_sub(*other)?))
}
}

View file

@ -43,34 +43,23 @@ impl SystemTime {
SystemTime(current_time(wasi::CLOCKID_REALTIME))
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime {
pub fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime {
SystemTime(Duration::from_nanos(ts))
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn to_wasi_timestamp(&self) -> Option<wasi::Timestamp> {
// FIXME: const TryInto
let ns = self.0.as_nanos();
if ns <= u64::MAX as u128 { Some(ns as u64) } else { None }
pub fn to_wasi_timestamp(&self) -> Option<wasi::Timestamp> {
self.0.as_nanos().try_into().ok()
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
// FIXME: ok_or_else with const closures
match self.0.checked_sub(other.0) {
Some(duration) => Ok(duration),
None => Err(other.0 - self.0),
}
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_add(*other)?))
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_sub(*other)?))
}
}

View file

@ -36,34 +36,23 @@ impl SystemTime {
SystemTime(Duration::new(now.seconds, now.nanoseconds))
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime {
pub fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime {
SystemTime(Duration::from_nanos(ts))
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn to_wasi_timestamp(&self) -> Option<wasi::Timestamp> {
// FIXME: const TryInto
let ns = self.0.as_nanos();
if ns <= u64::MAX as u128 { Some(ns as u64) } else { None }
pub fn to_wasi_timestamp(&self) -> Option<wasi::Timestamp> {
self.0.as_nanos().try_into().ok()
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
// FIXME: ok_or_else with const closures
match self.0.checked_sub(other.0) {
Some(duration) => Ok(duration),
None => Err(other.0 - self.0),
}
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_add(*other)?))
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_sub(*other)?))
}
}

View file

@ -72,8 +72,7 @@ impl SystemTime {
}
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
const fn from_intervals(intervals: i64) -> SystemTime {
fn from_intervals(intervals: i64) -> SystemTime {
SystemTime {
t: c::FILETIME {
dwLowDateTime: intervals as u32,
@ -82,13 +81,11 @@ impl SystemTime {
}
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
const fn intervals(&self) -> i64 {
fn intervals(&self) -> i64 {
(self.t.dwLowDateTime as i64) | ((self.t.dwHighDateTime as i64) << 32)
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
let me = self.intervals();
let other = other.intervals();
if me >= other {
@ -98,14 +95,12 @@ impl SystemTime {
}
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
let intervals = self.intervals().checked_add(checked_dur2intervals(other)?)?;
Some(SystemTime::from_intervals(intervals))
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
let intervals = self.intervals().checked_sub(checked_dur2intervals(other)?)?;
Some(SystemTime::from_intervals(intervals))
}
@ -155,18 +150,15 @@ impl Hash for SystemTime {
}
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
const fn checked_dur2intervals(dur: &Duration) -> Option<i64> {
// FIXME: const TryInto
let secs = dur
.as_secs()
fn checked_dur2intervals(dur: &Duration) -> Option<i64> {
dur.as_secs()
.checked_mul(INTERVALS_PER_SEC)?
.checked_add(dur.subsec_nanos() as u64 / 100)?;
if secs <= i64::MAX as u64 { Some(secs.cast_signed()) } else { None }
.checked_add(dur.subsec_nanos() as u64 / 100)?
.try_into()
.ok()
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
const fn intervals2dur(intervals: u64) -> Duration {
fn intervals2dur(intervals: u64) -> Duration {
Duration::new(intervals / INTERVALS_PER_SEC, ((intervals % INTERVALS_PER_SEC) * 100) as u32)
}

View file

@ -43,22 +43,15 @@ impl SystemTime {
SystemTime { 0: Duration::from_millis((upper as u64) << 32 | lower as u64) }
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
// FIXME: ok_or_else with const closures
match self.0.checked_sub(other.0) {
Some(duration) => Ok(duration),
None => Err(other.0 - self.0),
}
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_add(*other)?))
}
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_sub(*other)?))
}
}

View file

@ -551,13 +551,8 @@ impl SystemTime {
/// println!("{difference:?}");
/// ```
#[stable(feature = "time2", since = "1.8.0")]
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn duration_since(&self, earlier: SystemTime) -> Result<Duration, SystemTimeError> {
// FIXME: map_err in const
match self.0.sub_time(&earlier.0) {
Ok(time) => Ok(time),
Err(err) => Err(SystemTimeError(err)),
}
pub fn duration_since(&self, earlier: SystemTime) -> Result<Duration, SystemTimeError> {
self.0.sub_time(&earlier.0).map_err(SystemTimeError)
}
/// Returns the difference from this system time to the
@ -594,8 +589,7 @@ impl SystemTime {
/// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None`
/// otherwise.
#[stable(feature = "time_checked_add", since = "1.34.0")]
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_add(&self, duration: Duration) -> Option<SystemTime> {
pub fn checked_add(&self, duration: Duration) -> Option<SystemTime> {
self.0.checked_add_duration(&duration).map(SystemTime)
}
@ -603,15 +597,13 @@ impl SystemTime {
/// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None`
/// otherwise.
#[stable(feature = "time_checked_add", since = "1.34.0")]
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn checked_sub(&self, duration: Duration) -> Option<SystemTime> {
pub fn checked_sub(&self, duration: Duration) -> Option<SystemTime> {
self.0.checked_sub_duration(&duration).map(SystemTime)
}
}
#[stable(feature = "time2", since = "1.8.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
impl const Add<Duration> for SystemTime {
impl Add<Duration> for SystemTime {
type Output = SystemTime;
/// # Panics
@ -624,16 +616,14 @@ impl const Add<Duration> for SystemTime {
}
#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
impl const AddAssign<Duration> for SystemTime {
impl AddAssign<Duration> for SystemTime {
fn add_assign(&mut self, other: Duration) {
*self = *self + other;
}
}
#[stable(feature = "time2", since = "1.8.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
impl const Sub<Duration> for SystemTime {
impl Sub<Duration> for SystemTime {
type Output = SystemTime;
fn sub(self, dur: Duration) -> SystemTime {
@ -642,8 +632,7 @@ impl const Sub<Duration> for SystemTime {
}
#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
impl const SubAssign<Duration> for SystemTime {
impl SubAssign<Duration> for SystemTime {
fn sub_assign(&mut self, other: Duration) {
*self = *self - other;
}
@ -710,8 +699,7 @@ impl SystemTimeError {
/// ```
#[must_use]
#[stable(feature = "time2", since = "1.8.0")]
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
pub const fn duration(&self) -> Duration {
pub fn duration(&self) -> Duration {
self.0
}
}

View file

@ -48,6 +48,7 @@
- [\*-apple-visionos](platform-support/apple-visionos.md)
- [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md)
- [aarch64-unknown-linux-musl](platform-support/aarch64-unknown-linux-musl.md)
- [aarch64-unknown-none*](platform-support/aarch64-unknown-none.md)
- [aarch64_be-unknown-none-softfloat](platform-support/aarch64_be-unknown-none-softfloat.md)
- [aarch64_be-unknown-linux-musl](platform-support/aarch64_be-unknown-linux-musl.md)
- [amdgcn-amd-amdhsa](platform-support/amdgcn-amd-amdhsa.md)
@ -55,7 +56,9 @@
- [arm-none-eabi](platform-support/arm-none-eabi.md)
- [armv4t-none-eabi](platform-support/armv4t-none-eabi.md)
- [armv5te-none-eabi](platform-support/armv5te-none-eabi.md)
- [armv7r-none-eabi](platform-support/armv7r-none-eabi.md)
- [armv7a-none-eabi{,hf}](platform-support/armv7a-none-eabi.md)
- [armv7r-none-eabi{,hf}](platform-support/armv7r-none-eabi.md)
- [armebv7r-none-eabi{,hf}](platform-support/armebv7r-none-eabi.md)
- [armv8r-none-eabihf](platform-support/armv8r-none-eabihf.md)
- [thumbv6m-none-eabi](./platform-support/thumbv6m-none-eabi.md)
- [thumbv7em-none-eabi\*](./platform-support/thumbv7em-none-eabi.md)

View file

@ -134,7 +134,7 @@ As of `2025-01-02T`, the list of known names is as follows:
- `unix`
- `windows`
> Starting with 1.85.0, the `test` cfg is consider to be a "userspace" config
> Starting with 1.85.0, the `test` cfg is considered to be a "userspace" config
> despite being also set by `rustc` and should be managed by the build system itself.
Like with `values(any())`, well known names checking can be disabled by passing `cfg(any())`

View file

@ -149,22 +149,22 @@ target | std | notes
[`aarch64-apple-ios-sim`](platform-support/apple-ios.md) | ✓ | Apple iOS Simulator on ARM64
[`aarch64-linux-android`](platform-support/android.md) | ✓ | ARM64 Android
[`aarch64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | ARM64 Fuchsia
`aarch64-unknown-none` | * | Bare ARM64, hardfloat
`aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat
[`aarch64-unknown-none`](platform-support/aarch64-unknown-none.md) | * | Bare ARM64, hardfloat
[`aarch64-unknown-none-softfloat`](platform-support/aarch64-unknown-none.md) | * | Bare ARM64, softfloat
[`aarch64-unknown-uefi`](platform-support/unknown-uefi.md) | ? | ARM64 UEFI
[`arm-linux-androideabi`](platform-support/android.md) | ✓ | Armv6 Android
`arm-unknown-linux-musleabi` | ✓ | Armv6 Linux with musl 1.2.3
`arm-unknown-linux-musleabihf` | ✓ | Armv6 Linux with musl 1.2.3, hardfloat
[`arm64ec-pc-windows-msvc`](platform-support/arm64ec-pc-windows-msvc.md) | ✓ | Arm64EC Windows MSVC
[`armebv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian
[`armebv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat
[`armebv7r-none-eabi`](platform-support/armebv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian
[`armebv7r-none-eabihf`](platform-support/armebv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat
[`armv5te-unknown-linux-gnueabi`](platform-support/armv5te-unknown-linux-gnueabi.md) | ✓ | Armv5TE Linux (kernel 4.4+, glibc 2.23)
`armv5te-unknown-linux-musleabi` | ✓ | Armv5TE Linux with musl 1.2.3
[`armv7-linux-androideabi`](platform-support/android.md) | ✓ | Armv7-A Android
`armv7-unknown-linux-gnueabi` | ✓ | Armv7-A Linux (kernel 4.15+, glibc 2.27)
`armv7-unknown-linux-musleabi` | ✓ | Armv7-A Linux with musl 1.2.3
`armv7-unknown-linux-musleabihf` | ✓ | Armv7-A Linux with musl 1.2.3, hardfloat
[`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare Armv7-A
[`armv7a-none-eabi`](platform-support/armv7a-none-eabi.md) | * | Bare Armv7-A
[`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R
[`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, hardfloat
`i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2+, glibc 2.17, original Pentium) [^x86_32-floats-x87]

View file

@ -0,0 +1,78 @@
# `aarch64-unknown-none` and `aarch64-unknown-none-softfloat`
* **Tier: 2**
* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
Bare-metal targets for CPUs in the Armv8-A architecture family, running in AArch64 mode.
For the AArch32 mode carried over from Armv7-A, see
[`armv7a-none-eabi`](armv7a-none-eabi.md) instead.
Processors in this family include the [Arm Cortex-A35, 53, 76, etc][aarch64-cpus].
[aarch64-cpus]: https://en.wikipedia.org/wiki/Comparison_of_ARM_processors#ARMv8-A
## Target maintainers
[Rust Embedded Devices Working Group Arm Team]
[Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team
## Target CPU and Target Feature options
All AArch64 processors include an FPU. The difference between the `-none` and
`-none-softfloat` targets is whether the FPU is used for passing function arguments.
You may prefer the `-softfloat` target when writing a kernel or interfacing with
pre-compiled binaries that use the soft-float ABI.
When using the hardfloat targets, the minimum floating-point features assumed
are those of the `fp-armv8`, which excludes NEON SIMD support. If your
processor supports a different set of floating-point features than the default
expectations of `fp-armv8`, then these should also be enabled or disabled as
needed with `-C target-feature=(+/-)`. It is also possible to tell Rust (or
LLVM) that you have a specific model of Arm processor, using the
[`-Ctarget-cpu`][target-cpu] option. Doing so may change the default set of
target-features enabled.
[target-cpu]: https://doc.rust-lang.org/rustc/codegen-options/index.html#target-cpu
[target-feature]: https://doc.rust-lang.org/rustc/codegen-options/index.html#target-feature
## Requirements
These targets are cross-compiled and use static linking.
By default, the `lld` linker included with Rust will be used; however, you may
want to use the GNU linker instead. This can be obtained for Windows/Mac/Linux
from the [Arm Developer Website][arm-gnu-toolchain], or possibly from your OS's
package manager. To use it, add the following to your `.cargo/config.toml`:
```toml
[target.aarch64-unknown-none]
linker = "aarch64-none-elf-ld"
```
The GNU linker can also be used by specifying `aarch64-none-elf-gcc` as the
linker. This is needed when using GCC's link time optimization.
These targets don't provide a linker script, so you'll need to bring your own
according to the specific device you are using. Pass
`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use
`your_script.ld` during linking.
[arm-gnu-toolchain]: https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain
## Cross-compilation toolchains and C code
This target supports C code compiled with the `aarch64-none-elf` target
triple and a suitable `-march` or `-mcpu` flag.
## Start-up and Low-Level Code
The [Rust Embedded Devices Working Group Arm Team] maintain the
[`aarch64-cpu`] crate, which may be useful for writing bare-metal code using
this target.
The *TrustedFirmware* group also maintain [Rust crates for this
target](https://github.com/ArmFirmwareCrates).
[`aarch64-cpu`]: https://docs.rs/aarch64-cpu

View file

@ -12,10 +12,10 @@ their own document.
### Tier 2 Target List
- Arm A-Profile Architectures
- `armv7a-none-eabi`
- [`armv7a-none-eabi`](armv7a-none-eabi.md)
- Arm R-Profile Architectures
- [`armv7r-none-eabi` and `armv7r-none-eabihf`](armv7r-none-eabi.md)
- [`armebv7r-none-eabi` and `armebv7r-none-eabihf`](armv7r-none-eabi.md)
- [`armebv7r-none-eabi` and `armebv7r-none-eabihf`](armebv7r-none-eabi.md)
- Arm M-Profile Architectures
- [`thumbv6m-none-eabi`](thumbv6m-none-eabi.md)
- [`thumbv7m-none-eabi`](thumbv7m-none-eabi.md)
@ -28,7 +28,7 @@ their own document.
### Tier 3 Target List
- Arm A-Profile Architectures
- `armv7a-none-eabihf`
- [`armv7a-none-eabihf`](armv7a-none-eabi.md)
- Arm R-Profile Architectures
- [`armv8r-none-eabihf`](armv8r-none-eabihf.md)
- Arm M-Profile Architectures

View file

@ -0,0 +1,55 @@
# `armebv7r-none-eabi` and `armebv7r-none-eabihf`
* **Tier: 2**
* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
Bare-metal target for CPUs in the Armv7-R architecture family running in Big
Endian mode. These processors support dual ARM/Thumb mode, with ARM mode as
the default.
**NOTE:** You should almost always prefer the [little-endian
versions](armv7r-none-eabi.md) of these target. Big Endian Arm systems are
highly unusual.
Processors in this family include the [Arm Cortex-R4, 5, 7, and 8][cortex-r].
See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
`arm-none-eabi` targets.
[cortex-r]: https://en.wikipedia.org/wiki/ARM_Cortex-R
## Target maintainers
[@chrisnc](https://github.com/chrisnc)
## Requirements
Note that some variants of the Cortex-R have both big-endian instructions and
data. This configuration is known as BE-32, while data-only big-endianness is
known as BE-8. To build programs for BE-32 processors, the GNU linker must be
used with the `-mbe32` option. See [ARM Cortex-R Series Programmer's Guide:
Endianness][endianness] for more details about different endian modes.
When using the hardfloat targets, the minimum floating-point features assumed
are those of the `vfpv3-d16`, which includes single- and double-precision, with
16 double-precision registers. This floating-point unit appears in Cortex-R4F
and Cortex-R5F processors. See [VFP in the Cortex-R processors][vfp]
for more details on the possible FPU variants.
If your processor supports a different set of floating-point features than the
default expectations of `vfpv3-d16`, then these should also be enabled or
disabled as needed with `-C target-feature=(+/-)`.
[endianness]: https://developer.arm.com/documentation/den0042/a/Coding-for-Cortex-R-Processors/Endianness
[vfp]: https://developer.arm.com/documentation/den0042/a/Floating-Point/Floating-point-basics-and-the-IEEE-754-standard/VFP-in-the-Cortex-R-processors
## Start-up and Low-Level Code
The [Rust Embedded Devices Working Group Arm Team] maintain the [`cortex-ar`]
and [`cortex-r-rt`] crates, which may be useful for writing bare-metal code
using this target. Those crates include several examples which run in QEMU and
build using these targets.
[`cortex-ar`]: https://docs.rs/cortex-ar
[`cortex-r-rt`]: https://docs.rs/cortex-r-rt

View file

@ -1,6 +1,7 @@
# armv4t-none-eabi / thumbv4t-none-eabi
Tier 3
* **Tier: 3**
* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
These two targets are part of the [`arm-none-eabi`](arm-none-eabi.md) target
group, and all the information there applies.

View file

@ -1,6 +1,7 @@
# `armv5te-none-eabi`
**Tier: 3**
* **Tier: 3**
* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
Bare-metal target for any cpu in the Armv5TE architecture family, supporting
ARM/Thumb code interworking (aka `A32`/`T32`), with `A32` code as the default code

View file

@ -0,0 +1,70 @@
# `armv7a-none-eabi` and `armv7a-none-eabihf`
* **Tier: 2** for `armv7a-none-eabi`
* **Tier: 3** for `armv7a-none-eabihf`
* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
Bare-metal target for CPUs in the Armv7-A architecture family, supporting
dual ARM/Thumb mode, with ARM mode as the default.
Note, this is for processors running in AArch32 mode. For the AArch64 mode
added in Armv8-A, see [`aarch64-unknown-none`](aarch64-unknown-none.md) instead.
Processors in this family include the [Arm Cortex-A5, 8, 32, etc][cortex-a].
See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
`arm-none-eabi` targets.
[cortex-a]: https://en.wikipedia.org/wiki/ARM_Cortex-A
## Target maintainers
[Rust Embedded Devices Working Group Arm Team]
[Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team
## Requirements
Almost all Armv7-A processors include an FPU (a VFPv3 or a VFPv4). The
difference between the `-eabi` and `-eabihf` targets is whether the FPU is
used for passing function arguments. You may prefer the `-eabi` soft-float
target when the processor does not have a floating point unit or the compiled
code should not use the floating point unit.
When using the hardfloat targets, the minimum floating-point features assumed
are those of the VFPv3-D16, which includes single- and double-precision, with
16 double-precision registers. This floating-point unit appears in Cortex-A8
and Cortex-A9 processors. See [VFP in the Cortex-A processors][vfp] for more
details on the possible FPU variants.
If your processor supports a different set of floating-point features than the
default expectations of VFPv3-D16, then these should also be enabled or
disabled as needed with `-C target-feature=(+/-)`.
In general, the following four combinations are possible:
- VFPv3-D16, target feature `+vfp3` and `-d32`
- VFPv3-D32, target feature `+vfp3` and `+d32`
- VFPv4-D16, target feature `+vfp4` and `-d32`
- VFPv4-D32, target feature `+vfp4` and `+d32`
An Armv7-A processor may optionally include a NEON hardware unit which
provides Single Instruction Multiple Data (SIMD) operations. The
implementation of this unit implies VFPv3-D32. The target feature `+neon` may
be added to inform the compiler about the availability of NEON.
You can refer to the [arm-none-eabi](arm-none-eabi.md) documentation for a
generic guide on target feature and target CPU specification and how to enable
and disable them via `.cargo/config.toml` file.
[vfp]: https://developer.arm.com/documentation/den0013/0400/Floating-Point/Floating-point-basics-and-the-IEEE-754-standard/ARM-VFP
## Start-up and Low-Level Code
The [Rust Embedded Devices Working Group Arm Team] maintain the [`cortex-ar`]
and [`cortex-a-rt`] crates, which may be useful for writing bare-metal code
using this target. The [`cortex-ar` repository](https://github.com/rust-embedded/cortex-ar)
includes several examples which run in QEMU and build using these targets.
[`cortex-ar`]: https://docs.rs/cortex-ar
[`cortex-a-rt`]: https://docs.rs/cortex-a-rt

View file

@ -1,14 +1,13 @@
# `arm(eb)?v7r-none-eabi(hf)?`
# `armv7r-none-eabi` and `armv7r-none-eabihf`
**Tier: 2**
* **Tier: 2**
* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
Bare-metal target for CPUs in the Armv7-R architecture family, supporting
dual ARM/Thumb mode, with ARM mode as the default.
Processors in this family include the [Arm Cortex-R4, 5, 7, and 8][cortex-r].
The `eb` versions of this target generate code for big-endian processors.
See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
`arm-none-eabi` targets.
@ -17,16 +16,12 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
## Target maintainers
[@chrisnc](https://github.com/chrisnc)
[Rust Embedded Devices Working Group Arm Team]
[Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team
## Requirements
When using the big-endian version of this target, note that some variants of
the Cortex-R have both big-endian instructions and data. This configuration is
known as BE-32, while data-only big-endianness is known as BE-8. To build
programs for BE-32 processors, the GNU linker must be used with the `-mbe32`
option. See [ARM Cortex-R Series Programmer's Guide: Endianness][endianness]
for more details about different endian modes.
When using the hardfloat targets, the minimum floating-point features assumed
are those of the `vfpv3-d16`, which includes single- and double-precision, with
16 double-precision registers. This floating-point unit appears in Cortex-R4F
@ -41,7 +36,12 @@ disabled as needed with `-C target-feature=(+/-)`.
[vfp]: https://developer.arm.com/documentation/den0042/a/Floating-Point/Floating-point-basics-and-the-IEEE-754-standard/VFP-in-the-Cortex-R-processors
## Cross-compilation toolchains and C code
## Start-up and Low-Level Code
This target supports C code compiled with the `arm-none-eabi` target triple and
`-march=armv7-r` or a suitable `-mcpu` flag.
The [Rust Embedded Devices Working Group Arm Team] maintain the [`cortex-ar`]
and [`cortex-r-rt`] crates, which may be useful for writing bare-metal code
using this target. Those crates include several examples which run in QEMU and
build using these targets.
[`cortex-ar`]: https://docs.rs/cortex-ar
[`cortex-r-rt`]: https://docs.rs/cortex-r-rt

View file

@ -1,6 +1,7 @@
# `armv8r-none-eabihf`
**Tier: 3**
* **Tier: 3**
* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
Bare-metal target for CPUs in the Armv8-R architecture family, supporting
dual ARM/Thumb mode, with ARM mode as the default.
@ -17,6 +18,9 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
## Target maintainers
[@chrisnc](https://github.com/chrisnc)
[Rust Embedded Devices Working Group Arm Team]
[Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team
## Requirements
@ -34,7 +38,14 @@ Technical Reference Manual for more details.
[fpu]: https://developer.arm.com/documentation/100026/0104/Advanced-SIMD-and-floating-point-support/About-the-Advanced-SIMD-and-floating-point-support
## Cross-compilation toolchains and C code
### Table of supported CPUs for `armv8r-none-eabihf`
This target supports C code compiled with the `arm-none-eabi` target triple and
`-march=armv8-r` or a suitable `-mcpu` flag.
| CPU | FPU | Neon | Target CPU | Target Features |
|:----------- | --- |:---- |:---------------- |:------------------ |
| Any | SP | No | None | None |
| Cortex-R52 | SP | No | `cortex-r52` | `-fp64,-d32,-neon` |
| Cortex-R52 | DP | No | `cortex-r52` | `-neon` |
| Cortex-R52 | DP | Yes | `cortex-r52` | None |
| Cortex-R52+ | SP | No | `cortex-r52plus` | `-fp64,-d32,-neon` |
| Cortex-R52+ | DP | No | `cortex-r52plus` | `-neon` |
| Cortex-R52+ | DP | Yes | `cortex-r52plus` | None |

View file

@ -1,6 +1,7 @@
# `thumbv6m-none-eabi`
**Tier: 2**
* **Tier: 2**
* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
Bare-metal target for CPUs in the [Armv6-M] architecture family, supporting a
subset of the [T32 ISA][t32-isa].
@ -26,7 +27,7 @@ only option because there is no FPU support in [Armv6-M].
## Target maintainers
* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
## Target CPU and Target Feature options

View file

@ -1,6 +1,7 @@
# `thumbv7em-none-eabi` and `thumbv7em-none-eabihf`
**Tier: 2**
* **Tier: 2**
* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
Bare-metal target for CPUs in the [Armv7E-M] architecture family, supporting a
subset of the [T32 ISA][t32-isa].
@ -21,7 +22,7 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
## Target maintainers
* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
## Target CPU and Target Feature options

View file

@ -1,6 +1,7 @@
# `thumbv7m-none-eabi`
**Tier: 2**
* **Tier: 2**
* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
Bare-metal target for CPUs in the [Armv7-M] architecture family, supporting a
subset of the [T32 ISA][t32-isa].
@ -22,7 +23,7 @@ only option because there is no FPU support in [Armv7-M].
## Target maintainers
* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
## Target CPU and Target Feature options

View file

@ -1,6 +1,7 @@
# `thumbv8m.base-none-eabi`
**Tier: 2**
* **Tier: 2**
* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
Bare-metal target for CPUs in the Baseline [Armv8-M] architecture family,
supporting a subset of the [T32 ISA][t32-isa].
@ -22,7 +23,7 @@ only option because there is no FPU support in [Armv8-M] Baseline.
## Target maintainers
* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
## Target CPU and Target Feature options

View file

@ -1,6 +1,7 @@
# `thumbv8m.main-none-eabi` and `thumbv8m.main-none-eabihf`
**Tier: 2**
* **Tier: 2**
* **Library Support:** core and alloc (bare-metal, `#![no_std]`)
Bare-metal target for CPUs in the Mainline [Armv8-M] architecture family,
supporting a subset of the [T32 ISA][t32-isa].
@ -25,7 +26,7 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
## Target maintainers
* [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
## Target CPU and Target Feature options

View file

@ -0,0 +1,64 @@
//! Checks that the error messages start with a lowercased letter (except when allowed to).
use std::path::Path;
use fluent_syntax::ast::{Entry, Message, PatternElement};
use crate::walk::{filter_dirs, walk};
#[rustfmt::skip]
const ALLOWED_CAPITALIZED_WORDS: &[&str] = &[
// tidy-alphabetical-start
"ABI",
"ABIs",
"ADT",
"C",
"CGU",
"Ferris",
"MIR",
"OK",
"Rust",
"VS", // VS Code
// tidy-alphabetical-end
];
fn filter_fluent(path: &Path) -> bool {
if let Some(ext) = path.extension() { ext.to_str() != Some("ftl") } else { true }
}
fn is_allowed_capitalized_word(msg: &str) -> bool {
ALLOWED_CAPITALIZED_WORDS.iter().any(|word| {
msg.strip_prefix(word)
.map(|tail| tail.chars().next().map(|c| c == '-' || c.is_whitespace()).unwrap_or(true))
.unwrap_or_default()
})
}
fn check_lowercase(filename: &str, contents: &str, bad: &mut bool) {
let (Ok(parse) | Err((parse, _))) = fluent_syntax::parser::parse(contents);
for entry in &parse.body {
if let Entry::Message(msg) = entry
&& let Message { value: Some(pattern), .. } = msg
&& let [first_pattern, ..] = &pattern.elements[..]
&& let PatternElement::TextElement { value } = first_pattern
&& value.chars().next().is_some_and(char::is_uppercase)
&& !is_allowed_capitalized_word(value)
{
tidy_error!(
bad,
"{filename}: message `{value}` starts with an uppercase letter. Fix it or add it to `ALLOWED_CAPITALIZED_WORDS`"
);
}
}
}
pub fn check(path: &Path, bad: &mut bool) {
walk(
path,
|path, is_dir| filter_dirs(path) || (!is_dir && filter_fluent(path)),
&mut |ent, contents| {
check_lowercase(ent.path().to_str().unwrap(), contents, bad);
},
);
}

View file

@ -257,6 +257,7 @@ pub mod extra_checks;
pub mod features;
pub mod filenames;
pub mod fluent_alphabetical;
pub mod fluent_lowercase;
pub mod fluent_period;
mod fluent_used;
pub mod gcc_submodule;

View file

@ -121,6 +121,7 @@ fn main() {
check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose, &ci_info);
check!(fluent_alphabetical, &compiler_path, bless);
check!(fluent_period, &compiler_path);
check!(fluent_lowercase, &compiler_path);
check!(target_policy, &root_path);
check!(gcc_submodule, &root_path, &compiler_path);

View file

@ -0,0 +1,47 @@
//@ compile-flags: -C opt-level=3
#![feature(c_variadic)]
// Test that the inline attributes are accepted on C-variadic functions.
//
// Currently LLVM is unable to inline C-variadic functions, but that is valid because despite
// the name even `#[inline(always)]` is just a hint.
#[inline(always)]
unsafe extern "C" fn inline_always(mut ap: ...) -> u32 {
ap.arg::<u32>()
}
#[inline]
unsafe extern "C" fn inline(mut ap: ...) -> u32 {
ap.arg::<u32>()
}
#[inline(never)]
unsafe extern "C" fn inline_never(mut ap: ...) -> u32 {
ap.arg::<u32>()
}
#[cold]
unsafe extern "C" fn cold(mut ap: ...) -> u32 {
ap.arg::<u32>()
}
#[unsafe(no_mangle)]
#[inline(never)]
fn helper() {
// CHECK-LABEL: helper
// CHECK-LABEL: call c_variadic_inline::inline_always
// CHECK-LABEL: call c_variadic_inline::inline
// CHECK-LABEL: call c_variadic_inline::inline_never
// CHECK-LABEL: call c_variadic_inline::cold
unsafe {
inline_always(1);
inline(2);
inline_never(3);
cold(4);
}
}
fn main() {
helper()
}

View file

@ -0,0 +1,40 @@
//@ run-pass
//@ only-x86_64
//@ only-linux
#![feature(c_variadic)]
#[repr(C)]
#[derive(Debug, PartialEq)]
struct Data(i32, f64);
#[unsafe(naked)]
unsafe extern "C" fn c_variadic(_: ...) -> Data {
// This assembly was generated with GCC, because clang/LLVM is unable to
// optimize out the spilling of all registers to the stack.
core::arch::naked_asm!(
" sub rsp, 96",
" mov QWORD PTR [rsp-88], rdi",
" test al, al",
" je .L7",
" movaps XMMWORD PTR [rsp-40], xmm0",
".L7:",
" lea rax, [rsp+104]",
" mov rcx, QWORD PTR [rsp-40]",
" mov DWORD PTR [rsp-112], 0",
" mov QWORD PTR [rsp-104], rax",
" lea rax, [rsp-88]",
" mov QWORD PTR [rsp-96], rax",
" movq xmm0, rcx",
" mov eax, DWORD PTR [rsp-88]",
" mov DWORD PTR [rsp-108], 48",
" add rsp, 96",
" ret",
)
}
fn main() {
unsafe {
assert_eq!(c_variadic(1, 2.0), Data(1, 2.0));
assert_eq!(c_variadic(123, 4.56), Data(123, 4.56));
}
}

View file

@ -0,0 +1,14 @@
#![expect(incomplete_features)]
#![feature(c_variadic, explicit_tail_calls)]
#![allow(unused)]
unsafe extern "C" fn foo(mut ap: ...) -> u32 {
ap.arg::<u32>()
}
extern "C" fn bar() -> u32 {
unsafe { become foo(1, 2, 3) }
//~^ ERROR c-variadic functions can't be tail-called
}
fn main() {}

View file

@ -0,0 +1,8 @@
error: c-variadic functions can't be tail-called
--> $DIR/c-variadic.rs:10:14
|
LL | unsafe { become foo(1, 2, 3) }
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View file

@ -20,4 +20,4 @@ pub fn lib_main() {
unsafe { f(42); }
}
//~? ERROR Dlltool could not create import library with
//~? ERROR dlltool could not create import library with

View file

@ -1,4 +1,4 @@
error: Dlltool could not create import library with $DLLTOOL -d $DEF_FILE -D foo.dll -l $LIB_FILE $TARGET_MACHINE $ASM_FLAGS --no-leading-underscore $TEMP_PREFIX:
error: dlltool could not create import library with $DLLTOOL -d $DEF_FILE -D foo.dll -l $LIB_FILE $TARGET_MACHINE $ASM_FLAGS --no-leading-underscore $TEMP_PREFIX:
$DLLTOOL: Syntax error in def file $DEF_FILE:1␍