diff --git a/RELEASES.md b/RELEASES.md
index f180d740a3d17..a8ebb8343c017 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,17 @@
+Version 1.94.1 (2026-03-26)
+===========================
+
+
+
+* [Fix `std::thread::spawn` on wasm32-wasip1-threads](https://github.com/rust-lang/rust/pull/153634)
+* [Remove new methods added to `std::os::windows::fs::OpenOptionsExt`](https://github.com/rust-lang/rust/pull/153491)
+ The new methods were unstable, but the trait itself is not sealed and so
+ cannot be extended with non-default methods.
+* [[Clippy] Fix ICE in `match_same_arms`](https://github.com/rust-lang/rust-clippy/pull/16685)
+* [[Cargo] Update tar to 0.4.45](https://github.com/rust-lang/cargo/pull/16769)
+ This resolves CVE-2026-33055 and CVE-2026-33056. Users of crates.io are not affected.
+ See [blog](https://blog.rust-lang.org/2026/03/21/cve-2026-33056/) for more details.
+
Version 1.94.0 (2026-03-05)
==========================
diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs
index 73f3e589e2432..7fd46b31f7d83 100644
--- a/library/std/src/os/windows/fs.rs
+++ b/library/std/src/os/windows/fs.rs
@@ -138,6 +138,8 @@ impl FileExt for fs::File {
}
/// Windows-specific extensions to [`fs::OpenOptions`].
+// WARNING: This trait is not sealed. DON'T add any new methods!
+// Add them to OpenOptionsExt2 instead.
#[stable(feature = "open_options_ext", since = "1.10.0")]
pub trait OpenOptionsExt {
/// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`]
@@ -305,18 +307,6 @@ pub trait OpenOptionsExt {
/// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
#[stable(feature = "open_options_ext", since = "1.10.0")]
fn security_qos_flags(&mut self, flags: u32) -> &mut Self;
-
- /// If set to `true`, prevent the "last access time" of the file from being changed.
- ///
- /// Default to `false`.
- #[unstable(feature = "windows_freeze_file_times", issue = "149715")]
- fn freeze_last_access_time(&mut self, freeze: bool) -> &mut Self;
-
- /// If set to `true`, prevent the "last write time" of the file from being changed.
- ///
- /// Default to `false`.
- #[unstable(feature = "windows_freeze_file_times", issue = "149715")]
- fn freeze_last_write_time(&mut self, freeze: bool) -> &mut Self;
}
#[stable(feature = "open_options_ext", since = "1.10.0")]
@@ -345,7 +335,28 @@ impl OpenOptionsExt for OpenOptions {
self.as_inner_mut().security_qos_flags(flags);
self
}
+}
+
+#[unstable(feature = "windows_freeze_file_times", issue = "149715")]
+pub trait OpenOptionsExt2: Sealed {
+ /// If set to `true`, prevent the "last access time" of the file from being changed.
+ ///
+ /// Default to `false`.
+ #[unstable(feature = "windows_freeze_file_times", issue = "149715")]
+ fn freeze_last_access_time(&mut self, freeze: bool) -> &mut Self;
+
+ /// If set to `true`, prevent the "last write time" of the file from being changed.
+ ///
+ /// Default to `false`.
+ #[unstable(feature = "windows_freeze_file_times", issue = "149715")]
+ fn freeze_last_write_time(&mut self, freeze: bool) -> &mut Self;
+}
+
+#[unstable(feature = "sealed", issue = "none")]
+impl Sealed for OpenOptions {}
+#[unstable(feature = "windows_freeze_file_times", issue = "149715")]
+impl OpenOptionsExt2 for OpenOptions {
fn freeze_last_access_time(&mut self, freeze: bool) -> &mut Self {
self.as_inner_mut().freeze_last_access_time(freeze);
self
diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs
index 6f23c28c04d6a..430e699e098e6 100644
--- a/library/std/src/sys/thread/unix.rs
+++ b/library/std/src/sys/thread/unix.rs
@@ -49,7 +49,10 @@ impl Thread {
// WASI does not support threading via pthreads. While wasi-libc provides
// pthread stubs, pthread_create returns EAGAIN, which causes confusing
// errors. We return UNSUPPORTED_PLATFORM directly instead.
- if cfg!(target_os = "wasi") {
+
+ // NOTE: exempt `wasm32-wasip1-threads` from this check as `emnapi` has a working pthread
+ // implementation. See .
+ if cfg!(all(target_os = "wasi", not(all(target_env = "p1", target_feature = "atomics")))) {
return Err(io::Error::UNSUPPORTED_PLATFORM);
}
diff --git a/src/tools/cargo b/src/tools/cargo
index 85eff7c80277b..292f395c297d4 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit 85eff7c80277b57f78b11e28d14154ab12fcf643
+Subproject commit 292f395c297d4f99171325b0842ac4ea4ff3b386
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index c20217563d62b..3976529f96120 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -12,7 +12,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExpr, PatExprKind, PatKind, RangeEnd};
use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
use rustc_lint::{LateContext, LintContext};
-use rustc_middle::ty;
+use rustc_middle::ty::{self, TypeckResults};
use rustc_span::{ByteSymbol, ErrorGuaranteed, Span, Symbol};
use super::MATCH_SAME_ARMS;
@@ -61,7 +61,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
let check_eq_with_pat = |expr_a: &Expr<'_>, expr_b: &Expr<'_>| {
let mut local_map: HirIdMap = HirIdMap::default();
- let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
+ let eq_fallback = |a_typeck_results: &TypeckResults<'tcx>,
+ a: &Expr<'_>,
+ b_typeck_results: &TypeckResults<'tcx>,
+ b: &Expr<'_>| {
if let Some(a_id) = a.res_local_id()
&& let Some(b_id) = b.res_local_id()
&& let entry = match local_map.entry(a_id) {
@@ -71,7 +74,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
}
// the names technically don't have to match; this makes the lint more conservative
&& cx.tcx.hir_name(a_id) == cx.tcx.hir_name(b_id)
- && cx.typeck_results().expr_ty(a) == cx.typeck_results().expr_ty(b)
+ && a_typeck_results.expr_ty(a) == b_typeck_results.expr_ty(b)
&& pat_contains_local(lhs.pat, a_id)
&& pat_contains_local(rhs.pat, b_id)
{
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index 7b10c37de42df..d2e593fc17df8 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -9,6 +9,7 @@ use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp};
use rustc_lint::LateContext;
+use rustc_middle::ty::TypeckResults;
use rustc_middle::ty::adjustment::Adjust;
use rustc_span::Span;
use rustc_span::symbol::{Ident, Symbol};
@@ -136,7 +137,9 @@ impl<'tcx> OffendingFilterExpr<'tcx> {
// .map(|y| y[.acceptable_method()].unwrap())
&& let simple_equal = (receiver.res_local_id() == Some(filter_param_id)
&& map_arg_peeled.res_local_id() == Some(map_param_id))
- && let eq_fallback = (|a: &Expr<'_>, b: &Expr<'_>| {
+ && let eq_fallback =
+ (|a_typeck_results: &TypeckResults<'tcx>, a: &Expr<'_>,
+ b_typeck_results: &TypeckResults<'tcx>, b: &Expr<'_>| {
// in `filter(|x| ..)`, replace `*x` with `x`
let a_path = if !is_filter_param_ref
&& let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind
@@ -144,7 +147,7 @@ impl<'tcx> OffendingFilterExpr<'tcx> {
// let the filter closure arg and the map closure arg be equal
a_path.res_local_id() == Some(filter_param_id)
&& b.res_local_id() == Some(map_param_id)
- && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b)
+ && a_typeck_results.expr_ty_adjusted(a) == b_typeck_results.expr_ty_adjusted(b)
})
&& (simple_equal
|| SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(receiver, map_arg_peeled))
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index c7bb3a064a093..df121d24b6aea 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -26,7 +26,8 @@ use std::slice;
/// Callback that is called when two expressions are not equal in the sense of `SpanlessEq`, but
/// other conditions would make them equal.
-type SpanlessEqCallback<'a> = dyn FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a;
+type SpanlessEqCallback<'a, 'tcx> =
+ dyn FnMut(&TypeckResults<'tcx>, &Expr<'_>, &TypeckResults<'tcx>, &Expr<'_>) -> bool + 'a;
/// Determines how paths are hashed and compared for equality.
#[derive(Copy, Clone, Debug, Default)]
@@ -59,7 +60,7 @@ pub struct SpanlessEq<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
maybe_typeck_results: Option<(&'tcx TypeckResults<'tcx>, &'tcx TypeckResults<'tcx>)>,
allow_side_effects: bool,
- expr_fallback: Option>>,
+ expr_fallback: Option>>,
path_check: PathCheck,
}
@@ -94,7 +95,10 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
}
#[must_use]
- pub fn expr_fallback(self, expr_fallback: impl FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a) -> Self {
+ pub fn expr_fallback(
+ self,
+ expr_fallback: impl FnMut(&TypeckResults<'tcx>, &Expr<'_>, &TypeckResults<'tcx>, &Expr<'_>) -> bool + 'a,
+ ) -> Self {
Self {
expr_fallback: Some(Box::new(expr_fallback)),
..self
@@ -639,7 +643,15 @@ impl HirEqInterExpr<'_, '_, '_> {
) => false,
};
(is_eq && (!self.should_ignore(left) || !self.should_ignore(right)))
- || self.inner.expr_fallback.as_mut().is_some_and(|f| f(left, right))
+ || self
+ .inner
+ .maybe_typeck_results
+ .is_some_and(|(left_typeck_results, right_typeck_results)| {
+ self.inner
+ .expr_fallback
+ .as_mut()
+ .is_some_and(|f| f(left_typeck_results, left, right_typeck_results, right))
+ })
}
fn eq_exprs(&mut self, left: &[Expr<'_>], right: &[Expr<'_>]) -> bool {
diff --git a/src/tools/clippy/tests/ui/match_same_arms.fixed b/src/tools/clippy/tests/ui/match_same_arms.fixed
index 31684a5759fe9..8b16fd3193f5f 100644
--- a/src/tools/clippy/tests/ui/match_same_arms.fixed
+++ b/src/tools/clippy/tests/ui/match_same_arms.fixed
@@ -140,3 +140,19 @@ fn main() {
_ => false,
};
}
+
+fn issue16678() {
+ // ICE in Rust 1.94.0
+ match true {
+ true => {
+ fn wrapper(_arg: ()) {
+ _arg;
+ }
+ },
+ false => {
+ fn wrapper(_arg: ()) {
+ _arg;
+ }
+ },
+ }
+}
diff --git a/src/tools/clippy/tests/ui/match_same_arms.rs b/src/tools/clippy/tests/ui/match_same_arms.rs
index 39bee01bac22b..3b2d585c579d3 100644
--- a/src/tools/clippy/tests/ui/match_same_arms.rs
+++ b/src/tools/clippy/tests/ui/match_same_arms.rs
@@ -149,3 +149,19 @@ fn main() {
_ => false,
};
}
+
+fn issue16678() {
+ // ICE in Rust 1.94.0
+ match true {
+ true => {
+ fn wrapper(_arg: ()) {
+ _arg;
+ }
+ },
+ false => {
+ fn wrapper(_arg: ()) {
+ _arg;
+ }
+ },
+ }
+}
diff --git a/src/version b/src/version
index 8db4a57b3d020..df83a51c6cb9a 100644
--- a/src/version
+++ b/src/version
@@ -1 +1 @@
-1.94.0
+1.94.1