Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
0fae375
Constify Iterator-related methods and functions
Randl May 10, 2026
7cbc028
rustdoc: deterministic sorting for `doc_cfg` badges
shivendra02467 May 10, 2026
c328459
Clarify "infinite size" in cyclic-type diagnostic refers to the type …
onehr May 23, 2026
78a6b58
add red test
qaijuang May 26, 2026
cf3249c
coverage: Use original HIR info for synthetic by-move coroutine bodies
qaijuang May 26, 2026
f46fade
Emit uwtable annotation for modules
Darksonn May 26, 2026
581bf3c
Add tests for uwtable annotations on modules
Darksonn May 26, 2026
e724fa6
interpret/validity: properly treat zero-variant enums so that we do n…
RalfJung May 26, 2026
1f02e4d
std: Fix thread::available_parallelism on Redox targets
willnode May 27, 2026
12b3dd8
Limit the additional DLL to Windows
mati865 May 26, 2026
90fe8cc
Adjust UWTableKind comment ref to llvm type
Darksonn May 27, 2026
74c0a25
Rollup merge of #156970 - qaijuang:async_closure_coverage, r=Zalathar
GuillaumeGomez May 27, 2026
65561b8
Rollup merge of #156390 - Randl:iter_related_const, r=oli-obk
GuillaumeGomez May 27, 2026
ae771a9
Rollup merge of #156401 - shivendra02467:doc-cfg-sort-fix, r=Guillaum…
GuillaumeGomez May 27, 2026
0ed1e95
Rollup merge of #156845 - onehr:clarify-cyclic-type-149842, r=JohnTitor
GuillaumeGomez May 27, 2026
7d33b81
Rollup merge of #156973 - Darksonn:unwind-tables-module, r=nnethercote
GuillaumeGomez May 27, 2026
466b4d3
Rollup merge of #156985 - mati865:additional-llvm-dll-windows-only, r…
GuillaumeGomez May 27, 2026
1876cf4
Rollup merge of #156988 - RalfJung:validate-uninhabited, r=oli-obk
GuillaumeGomez May 27, 2026
45ed9ce
Rollup merge of #157002 - willnode:redox-nproc, r=bjorn3
GuillaumeGomez May 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ pub(crate) fn uwtable_attr(llcx: &llvm::Context, use_sync_unwind: Option<bool>)
// NOTE: We should determine if we even need async unwind tables, as they
// take have more overhead and if we can use sync unwind tables we
// probably should.
//
// Similar logic exists for the per-module uwtable annotation in `context.rs`.
let async_unwind = !use_sync_unwind.unwrap_or(false);
llvm::CreateUWTableAttr(llcx, async_unwind)
}
Expand Down
19 changes: 19 additions & 0 deletions compiler/rustc_codegen_llvm/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,25 @@ pub(crate) unsafe fn create_module<'ll>(
);
}

if sess.must_emit_unwind_tables() {
// This assertion checks that Max is the correct merge behavior.
// Async unwind tables are strictly more useful than sync uwtables.
const {
assert!((llvm::UWTableKind::None as u32) < (llvm::UWTableKind::Sync as u32));
assert!((llvm::UWTableKind::Sync as u32) < (llvm::UWTableKind::Async as u32));
}

llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Max,
"uwtable",
match sess.opts.unstable_opts.use_sync_unwind {
Some(true) => llvm::UWTableKind::Sync as u32,
Some(false) | None => llvm::UWTableKind::Async as u32,
},
);
}

// Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.)
if sess.is_sanitizer_kcfi_enabled() {
llvm::add_module_flag_u32(llmod, llvm::ModuleFlagMergeBehavior::Override, "kcfi", 1);
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,18 @@ pub(crate) enum DLLStorageClass {
DllExport = 2, // Function to be accessible from DLL.
}

/// Must match the layout of `llvm::UWTableKind`.
#[derive(Copy, Clone)]
#[repr(C)]
pub(crate) enum UWTableKind {
/// No unwind table requested
None = 0,
/// "Synchronous" unwind tables
Sync = 1,
/// "Asynchronous" unwind tables (instr precise)
Async = 2,
}

/// Must match the layout of `LLVMRustAttributeKind`.
/// Semantically a subset of the C++ enum llvm::Attribute::AttrKind,
/// though it is not ABI compatible (since it's a C++ enum)
Expand Down
33 changes: 17 additions & 16 deletions compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1353,6 +1353,16 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
interp_ok(())
}

#[inline]
fn visit_variantless(&mut self, val: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
let ty = val.layout.ty;
assert!(ty.is_enum(), "encountered non-enum variantless type `{ty}`");
throw_validation_failure!(
self.path,
format!("encountered a value of zero-variant enum `{ty}`")
);
}

#[inline]
fn visit_value(&mut self, val: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
trace!("visit_value: {:?}, {:?}", *val, val.layout);
Expand Down Expand Up @@ -1557,23 +1567,14 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
}
}

// *After* all of this, check further information stored in the layout.
// On leaf types like `!` or empty enums, this will raise the error.
// This means that for types wrapping such a type, we won't ever get here, but it's
// just the simplest way to check for this case.
//
// FIXME: We could avoid some redundant checks here. For newtypes wrapping
// scalars, we do the same check on every "level" (e.g., first we check
// the fields of MyNewtype, and then we check MyNewType again).
if val.layout.is_uninhabited() {
let ty = val.layout.ty;
throw_validation_failure!(
self.path,
format!("encountered a value of uninhabited type `{ty}`")
);
}
// Assert that we checked everything there is to check about this type.
assert!(
!val.layout.is_uninhabited(),
"a value of type `{}` passed validation but that type is uninhabited",
val.layout.ty
);
if cfg!(debug_assertions) {
// Check that we don't miss any new changes to layout computation in our checks above.
// Only run expensive checks when debug assertions are enabled.
match val.layout.backend_repr {
BackendRepr::Scalar(scalar_layout) => {
if !scalar_layout.is_uninit_valid() {
Expand Down
11 changes: 10 additions & 1 deletion compiler/rustc_const_eval/src/interpret/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
fn visit_box(&mut self, _box_ty: Ty<'tcx>, _v: &Self::V) -> InterpResult<'tcx> {
interp_ok(())
}
/// Visits the given type after it has been found to have no variants.
#[inline(always)]
fn visit_variantless(&mut self, _v: &Self::V) -> InterpResult<'tcx> {
interp_ok(())
}

/// Called each time we recurse down to a field of a "product-like" aggregate
/// (structs, tuples, arrays and the like, but not enums), passing in old (outer)
Expand Down Expand Up @@ -193,7 +198,11 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
self.visit_variant(v, idx, &inner)?;
}
// For single-variant layouts, we already did everything there is to do.
Variants::Single { .. } | Variants::Empty => {}
Variants::Single { .. } => {}
// Non-variant layouts need special treatment by the visitor.
Variants::Empty => {
self.visit_variantless(v)?;
}
}

interp_ok(())
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl<'tcx> TypeError<'tcx> {
}

match self {
TypeError::CyclicTy(_) => "cyclic type of infinite size".into(),
TypeError::CyclicTy(_) => "recursive type with infinite-size name".into(),
TypeError::CyclicConst(_) => "encountered a self-referencing constant".into(),
TypeError::Mismatch => "types differ".into(),
TypeError::PolarityMismatch(values) => {
Expand Down
13 changes: 10 additions & 3 deletions compiler/rustc_mir_transform/src/coverage/hir_info.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use rustc_hir as hir;
use rustc_hir::intravisit::{Visitor, walk_expr};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::Span;
use rustc_span::def_id::LocalDefId;

Expand All @@ -24,9 +24,16 @@ pub(crate) fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> E
// FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back
// to HIR for it.

// HACK: For synthetic MIR bodies (async closures), use the def id of the HIR body.
// Synthetic by-move coroutine bodies don't have useful HIR of their own.
// Use the original coroutine body instead. These synthetic bodies are
// created with a coroutine type, so we can inspect that type as-is.
if tcx.is_synthetic_mir(def_id) {
return extract_hir_info(tcx, tcx.local_parent(def_id));
let effective_def_id =
match *tcx.type_of(def_id).instantiate_identity().skip_normalization().kind() {
ty::Coroutine(coroutine_def_id, _) => coroutine_def_id.expect_local(),
_ => tcx.local_parent(def_id),
};
return extract_hir_info(tcx, effective_def_id);
}

let hir_node = tcx.hir_node_by_def_id(def_id);
Expand Down
9 changes: 6 additions & 3 deletions library/core/src/array/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ pub struct IntoIter<T, const N: usize> {

impl<T, const N: usize> IntoIter<T, N> {
#[inline]
fn unsize(&self) -> &InnerUnsized<T> {
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
const fn unsize(&self) -> &InnerUnsized<T> {
self.inner.deref()
}
#[inline]
fn unsize_mut(&mut self) -> &mut InnerUnsized<T> {
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
const fn unsize_mut(&mut self) -> &mut InnerUnsized<T> {
self.inner.deref_mut()
}
}
Expand Down Expand Up @@ -219,7 +221,8 @@ impl<T, const N: usize> IntoIter<T, N> {
/// Returns a mutable slice of all elements that have not been yielded yet.
#[stable(feature = "array_value_iter", since = "1.51.0")]
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [T] {
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
pub const fn as_mut_slice(&mut self) -> &mut [T] {
self.unsize_mut().as_mut_slice()
}
}
Expand Down
3 changes: 2 additions & 1 deletion library/core/src/array/iter/iter_inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ impl<T> PolymorphicIter<[MaybeUninit<T>]> {
}

#[inline]
pub(super) fn as_mut_slice(&mut self) -> &mut [T] {
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
pub(super) const fn as_mut_slice(&mut self) -> &mut [T] {
// SAFETY: We know that all elements within `alive` are properly initialized.
unsafe {
let slice = self.data.get_unchecked_mut(self.alive.clone());
Expand Down
4 changes: 3 additions & 1 deletion library/core/src/iter/traits/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,11 @@ impl<I: FusedIterator + ?Sized> FusedIterator for &mut I {}
/// of this trait must inspect [`Iterator::size_hint()`]’s upper bound.
#[unstable(feature = "trusted_len", issue = "37572")]
#[rustc_unsafe_specialization_marker]
pub unsafe trait TrustedLen: Iterator {}
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
pub const unsafe trait TrustedLen: [const] Iterator {}

#[unstable(feature = "trusted_len", issue = "37572")]
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
unsafe impl<I: TrustedLen + ?Sized> TrustedLen for &mut I {}

/// An iterator that when yielding an item will have taken at least one element
Expand Down
12 changes: 10 additions & 2 deletions library/core/src/ops/control_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,11 @@ impl<T> ControlFlow<T, T> {
impl<R: ops::Try> ControlFlow<R, R::Output> {
/// Creates a `ControlFlow` from any type implementing `Try`.
#[inline]
pub(crate) fn from_try(r: R) -> Self {
#[rustc_const_unstable(feature = "const_control_flow", issue = "148739")]
pub(crate) const fn from_try(r: R) -> Self
where
R: [const] ops::Try,
{
match R::branch(r) {
ControlFlow::Continue(v) => ControlFlow::Continue(v),
ControlFlow::Break(v) => ControlFlow::Break(R::from_residual(v)),
Expand All @@ -436,7 +440,11 @@ impl<R: ops::Try> ControlFlow<R, R::Output> {

/// Converts a `ControlFlow` into any type implementing `Try`.
#[inline]
pub(crate) fn into_try(self) -> R {
#[rustc_const_unstable(feature = "const_control_flow", issue = "148739")]
pub(crate) const fn into_try(self) -> R
where
R: [const] ops::Try,
{
match self {
ControlFlow::Continue(v) => R::from_output(v),
ControlFlow::Break(v) => v,
Expand Down
10 changes: 8 additions & 2 deletions library/core/src/ops/try_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,8 +416,14 @@ impl<T> NeverShortCircuit<T> {
}

#[inline]
pub(crate) fn wrap_mut_2<A, B>(mut f: impl FnMut(A, B) -> T) -> impl FnMut(A, B) -> Self {
move |a, b| NeverShortCircuit(f(a, b))
#[rustc_const_unstable(feature = "const_array", issue = "147606")]
pub(crate) const fn wrap_mut_2<A, B, F>(
mut f: F,
) -> impl [const] FnMut(A, B) -> Self + [const] Destruct
where
F: [const] FnMut(A, B) -> T + [const] Destruct,
{
const move |a, b| NeverShortCircuit(f(a, b))
}
}

Expand Down
11 changes: 8 additions & 3 deletions library/core/src/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1748,8 +1748,12 @@ impl<T> Option<T> {
/// ```
#[inline]
#[stable(feature = "option_entry", since = "1.20.0")]
pub fn get_or_insert(&mut self, value: T) -> &mut T {
self.get_or_insert_with(|| value)
#[rustc_const_unstable(feature = "const_option_ops", issue = "143956")]
pub const fn get_or_insert(&mut self, value: T) -> &mut T
where
T: [const] Destruct,
{
self.get_or_insert_with(const || value)
}

/// Inserts the default value into the option if it is [`None`], then
Expand Down Expand Up @@ -2649,7 +2653,8 @@ impl<A> ExactSizeIterator for IntoIter<A> {}
impl<A> FusedIterator for IntoIter<A> {}

#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<A> TrustedLen for IntoIter<A> {}
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
unsafe impl<A> const TrustedLen for IntoIter<A> {}

/// The iterator produced by [`Option::into_flat_iter`]. See its documentation for more.
#[derive(Clone, Debug)]
Expand Down
7 changes: 6 additions & 1 deletion library/core/src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1682,7 +1682,12 @@ impl<T, E> Result<T, E> {
#[inline]
#[track_caller]
#[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
pub unsafe fn unwrap_err_unchecked(self) -> E {
#[rustc_const_unstable(feature = "const_result_unwrap_unchecked", issue = "148714")]
pub const unsafe fn unwrap_err_unchecked(self) -> E
where
T: [const] Destruct,
E: [const] Destruct,
{
match self {
// SAFETY: the safety contract must be upheld by the caller.
Ok(_) => unsafe { hint::unreachable_unchecked() },
Expand Down
3 changes: 2 additions & 1 deletion library/core/src/tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ macro_rules! tuple_impls {
maybe_tuple_doc! {
$($T)+ @
#[stable(feature = "rust1", since = "1.0.0")]
impl<$($T: Default),+> Default for ($($T,)+) {
#[rustc_const_unstable(feature = "const_default", issue = "143894")]
impl<$($T: [const] Default),+> const Default for ($($T,)+) {
#[inline]
fn default() -> ($($T,)+) {
($({ let x: $T = Default::default(); x},)+)
Expand Down
3 changes: 2 additions & 1 deletion library/std/src/sys/thread/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
target_os = "aix",
target_vendor = "apple",
target_os = "cygwin",
target_os = "redox",
target_os = "wasi",
) => {
#[allow(unused_assignments)]
Expand Down Expand Up @@ -316,7 +317,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
}
}
_ => {
// FIXME: implement on Redox, l4re
// FIXME: implement on l4re
Err(io::const_error!(io::ErrorKind::Unsupported, "getting the number of hardware threads is not supported on the target platform"))
}
}
Expand Down
6 changes: 4 additions & 2 deletions src/bootstrap/src/core/build_steps/dist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2591,8 +2591,10 @@ pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection
// To workaround lack of rpath on Windows, we bundle another copy of
// the LLVM DLL to make rust-lld and llvm-tools work when `sysroot/bin`
// is missing from PATH, i.e. when they not launched by rustc.
let dst_libdir = sysroot.join("lib/rustlib").join(target).join("bin");
maybe_install_llvm(builder, target, &dst_libdir, false);
if target.triple.contains("windows") {
let dst_libdir = sysroot.join("lib/rustlib").join(target).join("bin");
maybe_install_llvm(builder, target, &dst_libdir, false);
}
}
}

Expand Down
Loading
Loading