Skip to content

Commit a015919

Browse files
committed
Auto merge of #146526 - jhpratt:rollup-afb1dgo, r=jhpratt
Rollup of 8 pull requests Successful merges: - #113095 (Document `become` keyword) - #146159 (Some hygiene doc improvements) - #146171 (tidy: check that error messages don't start with a capitalized letter) - #146419 (Update the arm-* and aarch64-* platform docs.) - #146473 (Revert "Constify SystemTime methods") - #146506 (Fix small typo in check-cfg.md) - #146517 (fix Condvar::wait_timeout docs) - #146521 (document `core::ffi::VaArgSafe`) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 02c7b1a + da1c27d commit a015919

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+674
-256
lines changed

compiler/rustc_codegen_ssa/messages.ftl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ codegen_ssa_cpu_required = target requires explicitly specifying a cpu with `-C
3131
codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
3232
3333
codegen_ssa_dlltool_fail_import_library =
34-
Dlltool could not create import library with {$dlltool_path} {$dlltool_args}:
34+
dlltool could not create import library with {$dlltool_path} {$dlltool_args}:
3535
{$stdout}
3636
{$stderr}
3737

compiler/rustc_passes/messages.ftl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ passes_const_stable_not_stable =
7575
.label = attribute specified here
7676
7777
passes_custom_mir_incompatible_dialect_and_phase =
78-
The {$dialect} dialect is not compatible with the {$phase} phase
78+
the {$dialect} dialect is not compatible with the {$phase} phase
7979
.dialect_span = this dialect...
8080
.phase_span = ... is not compatible with this phase
8181

compiler/rustc_span/src/hygiene.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ use crate::symbol::{Symbol, kw, sym};
4646
use crate::{DUMMY_SP, HashStableContext, Span, SpanDecoder, SpanEncoder, with_session_globals};
4747

4848
/// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks".
49+
///
50+
/// See <https://rustc-dev-guide.rust-lang.org/macro-expansion.html> for more explanation.
4951
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
5052
pub struct SyntaxContext(u32);
5153

@@ -61,7 +63,10 @@ pub type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency);
6163

6264
#[derive(Clone, Copy, Debug)]
6365
struct SyntaxContextData {
66+
/// The last macro expansion in the chain.
67+
/// (Here we say the most deeply nested macro expansion is the "outermost" expansion.)
6468
outer_expn: ExpnId,
69+
/// Transparency of the last macro expansion
6570
outer_transparency: Transparency,
6671
parent: SyntaxContext,
6772
/// This context, but with all transparent and semi-opaque expansions filtered away.
@@ -450,11 +455,13 @@ impl HygieneData {
450455
self.syntax_context_data[ctxt.0 as usize].opaque_and_semiopaque
451456
}
452457

458+
/// See [`SyntaxContextData::outer_expn`]
453459
#[inline]
454460
fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId {
455461
self.syntax_context_data[ctxt.0 as usize].outer_expn
456462
}
457463

464+
/// The last macro expansion and its Transparency
458465
#[inline]
459466
fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) {
460467
let data = &self.syntax_context_data[ctxt.0 as usize];
@@ -900,6 +907,7 @@ impl SyntaxContext {
900907
HygieneData::with(|data| data.normalize_to_macro_rules(self))
901908
}
902909

910+
/// See [`SyntaxContextData::outer_expn`]
903911
#[inline]
904912
pub fn outer_expn(self) -> ExpnId {
905913
HygieneData::with(|data| data.outer_expn(self))
@@ -912,6 +920,7 @@ impl SyntaxContext {
912920
HygieneData::with(|data| data.expn_data(data.outer_expn(self)).clone())
913921
}
914922

923+
/// See [`HygieneData::outer_mark`]
915924
#[inline]
916925
fn outer_mark(self) -> (ExpnId, Transparency) {
917926
HygieneData::with(|data| data.outer_mark(self))
@@ -982,19 +991,20 @@ impl Span {
982991
#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)]
983992
pub struct ExpnData {
984993
// --- The part unique to each expansion.
985-
/// The kind of this expansion - macro or compiler desugaring.
986994
pub kind: ExpnKind,
987-
/// The expansion that produced this expansion.
995+
/// The expansion that contains the definition of the macro for this expansion.
988996
pub parent: ExpnId,
989-
/// The location of the actual macro invocation or syntax sugar , e.g.
990-
/// `let x = foo!();` or `if let Some(y) = x {}`
997+
/// The span of the macro call which produced this expansion.
998+
///
999+
/// This span will typically have a different `ExpnData` and `call_site`.
1000+
/// This recursively traces back through any macro calls which expanded into further
1001+
/// macro calls, until the "source call-site" is reached at the root SyntaxContext.
1002+
/// For example, if `food!()` expands to `fruit!()` which then expands to `grape`,
1003+
/// then the call-site of `grape` is `fruit!()` and the call-site of `fruit!()`
1004+
/// is `food!()`.
9911005
///
992-
/// This may recursively refer to other macro invocations, e.g., if
993-
/// `foo!()` invoked `bar!()` internally, and there was an
994-
/// expression inside `bar!`; the call_site of the expression in
995-
/// the expansion would point to the `bar!` invocation; that
996-
/// call_site span would have its own ExpnData, with the call_site
997-
/// pointing to the `foo!` invocation.
1006+
/// For a desugaring expansion, this is the span of the expression or node that was
1007+
/// desugared.
9981008
pub call_site: Span,
9991009
/// Used to force two `ExpnData`s to have different `Fingerprint`s.
10001010
/// Due to macro expansion, it's possible to end up with two `ExpnId`s

compiler/rustc_span/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -710,8 +710,8 @@ impl Span {
710710
if !ctxt.is_root() { ctxt.outer_expn_data().call_site.source_callsite() } else { self }
711711
}
712712

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

library/core/src/ffi/va_list.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -202,18 +202,23 @@ mod sealed {
202202
impl<T> Sealed for *const T {}
203203
}
204204

205-
/// Trait which permits the allowed types to be used with [`VaListImpl::arg`].
205+
/// Types that are valid to read using [`VaListImpl::arg`].
206206
///
207207
/// # Safety
208208
///
209-
/// This trait must only be implemented for types that C passes as varargs without implicit promotion.
209+
/// The standard library implements this trait for primitive types that are
210+
/// expected to have a variable argument application-binary interface (ABI) on all
211+
/// platforms.
210212
///
211-
/// In C varargs, integers smaller than [`c_int`] and floats smaller than [`c_double`]
212-
/// are implicitly promoted to [`c_int`] and [`c_double`] respectively. Implementing this trait for
213-
/// types that are subject to this promotion rule is invalid.
213+
/// When C passes variable arguments, integers smaller than [`c_int`] and floats smaller
214+
/// than [`c_double`] are implicitly promoted to [`c_int`] and [`c_double`] respectively.
215+
/// Implementing this trait for types that are subject to this promotion rule is invalid.
214216
///
215217
/// [`c_int`]: core::ffi::c_int
216218
/// [`c_double`]: core::ffi::c_double
219+
// We may unseal this trait in the future, but currently our `va_arg` implementations don't support
220+
// types with an alignment larger than 8, or with a non-scalar layout. Inline assembly can be used
221+
// to accept unsupported types in the meantime.
217222
pub unsafe trait VaArgSafe: sealed::Sealed {}
218223

219224
// 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 {}
233238
unsafe impl<T> VaArgSafe for *const T {}
234239

235240
impl<'f> VaListImpl<'f> {
236-
/// Advance to the next arg.
241+
/// Advance to and read the next variable argument.
242+
///
243+
/// # Safety
244+
///
245+
/// This function is only sound to call when the next variable argument:
246+
///
247+
/// - has a type that is ABI-compatible with the type `T`
248+
/// - has a value that is a properly initialized value of type `T`
249+
///
250+
/// Calling this function with an incompatible type, an invalid value, or when there
251+
/// are no more variable arguments, is unsound.
252+
///
253+
/// [valid]: https://doc.rust-lang.org/nightly/nomicon/what-unsafe-does.html
237254
#[inline]
238255
pub unsafe fn arg<T: VaArgSafe>(&mut self) -> T {
239256
// SAFETY: the caller must uphold the safety contract for `va_arg`.

library/std/src/keyword_docs.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,6 +1257,108 @@ mod ref_keyword {}
12571257
/// [`async`]: ../std/keyword.async.html
12581258
mod return_keyword {}
12591259

1260+
#[doc(keyword = "become")]
1261+
//
1262+
/// Perform a tail-call of a function.
1263+
///
1264+
/// <div class="warning">
1265+
///
1266+
/// `feature(explicit_tail_calls)` is currently incomplete and may not work properly.
1267+
/// </div>
1268+
///
1269+
/// When tail calling a function, instead of its stack frame being added to the
1270+
/// stack, the stack frame of the caller is directly replaced with the callee's.
1271+
/// This means that as long as a loop in a call graph only uses tail calls, the
1272+
/// stack growth will be bounded.
1273+
///
1274+
/// This is useful for writing functional-style code (since it prevents recursion
1275+
/// from exhausting resources) or for code optimization (since a tail call
1276+
/// *might* be cheaper than a normal call, tail calls can be used in a similar
1277+
/// manner to computed goto).
1278+
///
1279+
/// Example of using `become` to implement functional-style `fold`:
1280+
/// ```
1281+
/// #![feature(explicit_tail_calls)]
1282+
/// #![expect(incomplete_features)]
1283+
///
1284+
/// fn fold<T: Copy, S>(slice: &[T], init: S, f: impl Fn(S, T) -> S) -> S {
1285+
/// match slice {
1286+
/// // without `become`, on big inputs this could easily overflow the
1287+
/// // stack. using a tail call guarantees that the stack will not grow unboundedly
1288+
/// [first, rest @ ..] => become fold(rest, f(init, *first), f),
1289+
/// [] => init,
1290+
/// }
1291+
/// }
1292+
/// ```
1293+
///
1294+
/// Compilers can already perform "tail call optimization" -- they can replace normal
1295+
/// calls with tail calls, although there are no guarantees that this will be done.
1296+
/// However, to perform TCO, the call needs to be the last thing that happens
1297+
/// in the functions and be returned from it. This requirement is often broken
1298+
/// by drop code for locals, which is run after computing the return expression:
1299+
///
1300+
/// ```
1301+
/// fn example() {
1302+
/// let string = "meow".to_owned();
1303+
/// println!("{string}");
1304+
/// return help(); // this is *not* the last thing that happens in `example`...
1305+
/// }
1306+
///
1307+
/// // ... because it is desugared to this:
1308+
/// fn example_desugared() {
1309+
/// let string = "meow".to_owned();
1310+
/// println!("{string}");
1311+
/// let tmp = help();
1312+
/// drop(string);
1313+
/// return tmp;
1314+
/// }
1315+
///
1316+
/// fn help() {}
1317+
/// ```
1318+
///
1319+
/// For this reason, `become` also changes the drop order, such that locals are
1320+
/// dropped *before* evaluating the call.
1321+
///
1322+
/// In order to guarantee that the compiler can perform a tail call, `become`
1323+
/// currently has these requirements:
1324+
/// 1. callee and caller must have the same ABI, arguments, and return type
1325+
/// 2. callee and caller must not have varargs
1326+
/// 3. caller must not be marked with `#[track_caller]`
1327+
/// - callee is allowed to be marked with `#[track_caller]` as otherwise
1328+
/// adding `#[track_caller]` would be a breaking change. if callee is
1329+
/// marked with `#[track_caller]` a tail call is not guaranteed.
1330+
/// 4. callee and caller cannot be a closure
1331+
/// (unless it's coerced to a function pointer)
1332+
///
1333+
/// It is possible to tail-call a function pointer:
1334+
/// ```
1335+
/// #![feature(explicit_tail_calls)]
1336+
/// #![expect(incomplete_features)]
1337+
///
1338+
/// #[derive(Copy, Clone)]
1339+
/// enum Inst { Inc, Dec }
1340+
///
1341+
/// fn dispatch(stream: &[Inst], state: u32) -> u32 {
1342+
/// const TABLE: &[fn(&[Inst], u32) -> u32] = &[increment, decrement];
1343+
/// match stream {
1344+
/// [inst, rest @ ..] => become TABLE[*inst as usize](rest, state),
1345+
/// [] => state,
1346+
/// }
1347+
/// }
1348+
///
1349+
/// fn increment(stream: &[Inst], state: u32) -> u32 {
1350+
/// become dispatch(stream, state + 1)
1351+
/// }
1352+
///
1353+
/// fn decrement(stream: &[Inst], state: u32) -> u32 {
1354+
/// become dispatch(stream, state - 1)
1355+
/// }
1356+
///
1357+
/// let program = &[Inst::Inc, Inst::Inc, Inst::Dec, Inst::Inc];
1358+
/// assert_eq!(dispatch(program, 0), 2);
1359+
/// ```
1360+
mod become_keyword {}
1361+
12601362
#[doc(keyword = "self")]
12611363
//
12621364
/// The receiver of a method, or the current module.

library/std/src/lib.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,6 @@
284284
#![feature(core_float_math)]
285285
#![feature(decl_macro)]
286286
#![feature(deprecated_suggestion)]
287-
#![feature(derive_const)]
288287
#![feature(doc_cfg)]
289288
#![feature(doc_cfg_hide)]
290289
#![feature(doc_masked)]
@@ -332,11 +331,7 @@
332331
#![feature(cfg_select)]
333332
#![feature(char_internals)]
334333
#![feature(clone_to_uninit)]
335-
#![feature(const_cmp)]
336334
#![feature(const_convert)]
337-
#![feature(const_ops)]
338-
#![feature(const_option_ops)]
339-
#![feature(const_try)]
340335
#![feature(core_intrinsics)]
341336
#![feature(core_io_borrowed_buf)]
342337
#![feature(drop_guard)]

library/std/src/sync/nonpoison/condvar.rs

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

library/std/src/sync/poison/condvar.rs

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

library/std/src/sys/pal/hermit/time.rs

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,8 @@ impl Timespec {
2525
Timespec { t: timespec { tv_sec, tv_nsec } }
2626
}
2727

28-
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
29-
const fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
30-
// FIXME: const PartialOrd
31-
let mut cmp = self.t.tv_sec - other.t.tv_sec;
32-
if cmp == 0 {
33-
cmp = self.t.tv_nsec as i64 - other.t.tv_nsec as i64;
34-
}
35-
36-
if cmp >= 0 {
28+
fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
29+
if self >= other {
3730
Ok(if self.t.tv_nsec >= other.t.tv_nsec {
3831
Duration::new(
3932
(self.t.tv_sec - other.t.tv_sec) as u64,
@@ -53,22 +46,20 @@ impl Timespec {
5346
}
5447
}
5548

56-
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
57-
const fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
49+
fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
5850
let mut secs = self.t.tv_sec.checked_add_unsigned(other.as_secs())?;
5951

6052
// Nano calculations can't overflow because nanos are <1B which fit
6153
// in a u32.
62-
let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
63-
if nsec >= NSEC_PER_SEC as u32 {
64-
nsec -= NSEC_PER_SEC as u32;
54+
let mut nsec = other.subsec_nanos() + u32::try_from(self.t.tv_nsec).unwrap();
55+
if nsec >= NSEC_PER_SEC.try_into().unwrap() {
56+
nsec -= u32::try_from(NSEC_PER_SEC).unwrap();
6557
secs = secs.checked_add(1)?;
6658
}
6759
Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } })
6860
}
6961

70-
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
71-
const fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
62+
fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
7263
let mut secs = self.t.tv_sec.checked_sub_unsigned(other.as_secs())?;
7364

7465
// Similar to above, nanos can't overflow.
@@ -222,18 +213,15 @@ impl SystemTime {
222213
SystemTime(time)
223214
}
224215

225-
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
226-
pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
216+
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
227217
self.0.sub_timespec(&other.0)
228218
}
229219

230-
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
231-
pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
220+
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
232221
Some(SystemTime(self.0.checked_add_duration(other)?))
233222
}
234223

235-
#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
236-
pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
224+
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
237225
Some(SystemTime(self.0.checked_sub_duration(other)?))
238226
}
239227
}

0 commit comments

Comments
 (0)