Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
675ba38
feat: add `from_fn_ptr` to `Waker` and `LocalWaker`
Ddystopia Aug 31, 2025
8537abb
Stabilize `fmt::{from_fn, FromFn}` under feature `fmt_from_fn`
coolreader18 Aug 27, 2025
f8d7b41
Reword docs slightly
coolreader18 Aug 27, 2025
859ae05
Remove some feature(debug_closure_helpers) attributes
coolreader18 Aug 27, 2025
93c8bf1
Remove F: Fn bound from FromFn struct
coolreader18 Sep 19, 2025
471f2ba
library: std: sys: net: uefi: tcp: Implement write_vectored
Ayush1325 Sep 7, 2025
1bc898e
test for aarch64-unknown-uefi
Jamesbarford Nov 3, 2025
4959d18
Rename -Zno-jump-tables to -Zjump-tables=<bool>
pmur Aug 28, 2025
bb9d800
Stabilize -Zjump-tables=<bool> into -Cjump-table=<bool>
pmur Aug 28, 2025
a78ba93
Improve documentation of -Cjump-tables
pmur Sep 11, 2025
b24b7bd
Update books
rustbot Nov 3, 2025
97e69d1
tidy: Fix false positives with absolute repo paths in `pal.rs` `check()`
Enselic Nov 3, 2025
fd11125
CI: rfl: move to temporary commit to support `-Cjump-tables=n`
ojeda Nov 1, 2025
4ab1fc5
Provide more context on `Fn` closure modifying binding
estebank Nov 17, 2024
75835fb
Repoint Waker::from_fn_ptr from feature request issue to tracking issue
dtolnay Nov 4, 2025
ea4e037
Rollup merge of #133149 - estebank:niko-rustnation, r=wesleywiser
Zalathar Nov 4, 2025
22e4575
Rollup merge of #145915 - coolreader18:stabilize-fmt_from_fn, r=dtolnay
Zalathar Nov 4, 2025
b618119
Rollup merge of #145974 - pmur:murp/stabilize-zno-jump-tables, r=wesl…
Zalathar Nov 4, 2025
149eb1a
Rollup merge of #146057 - Ddystopia:waker-fn, r=dtolnay
Zalathar Nov 4, 2025
5eef85c
Rollup merge of #146301 - Ayush1325:uefi-box, r=joboet
Zalathar Nov 4, 2025
f41c2e0
Rollup merge of #148437 - Jamesbarford:test/issue-98254, r=jieyouxu
Zalathar Nov 4, 2025
1d6aecb
Rollup merge of #148448 - rustbot:docs-update, r=ehuss
Zalathar Nov 4, 2025
0bded52
Rollup merge of #148451 - Enselic:tidy-fix, r=clubby789
Zalathar Nov 4, 2025
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
58 changes: 50 additions & 8 deletions compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
}
}
PlaceRef { local: _, projection: [proj_base @ .., ProjectionElem::Deref] } => {
if the_place_err.local == ty::CAPTURE_STRUCT_LOCAL
PlaceRef { local, projection: [proj_base @ .., ProjectionElem::Deref] } => {
if local == ty::CAPTURE_STRUCT_LOCAL
&& proj_base.is_empty()
&& !self.upvars.is_empty()
{
Expand All @@ -165,10 +165,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
", as `Fn` closures cannot mutate their captured variables".to_string()
}
} else {
let source = self.borrowed_content_source(PlaceRef {
local: the_place_err.local,
projection: proj_base,
});
let source =
self.borrowed_content_source(PlaceRef { local, projection: proj_base });
let pointer_type = source.describe_for_immutable_place(self.infcx.tcx);
opt_source = Some(source);
if let Some(desc) = self.describe_place(access_place.as_ref()) {
Expand Down Expand Up @@ -540,6 +538,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
PlaceRef { local, projection: [ProjectionElem::Deref] }
if local == ty::CAPTURE_STRUCT_LOCAL && !self.upvars.is_empty() =>
{
self.point_at_binding_outside_closure(&mut err, local, access_place);
self.expected_fn_found_fn_mut_call(&mut err, span, act);
}

Expand Down Expand Up @@ -958,6 +957,50 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
}

/// When modifying a binding from inside of an `Fn` closure, point at the binding definition.
fn point_at_binding_outside_closure(
&self,
err: &mut Diag<'_>,
local: Local,
access_place: Place<'tcx>,
) {
let place = access_place.as_ref();
for (index, elem) in place.projection.into_iter().enumerate() {
if let ProjectionElem::Deref = elem {
if index == 0 {
if self.body.local_decls[local].is_ref_for_guard() {
continue;
}
if let LocalInfo::StaticRef { .. } = *self.body.local_decls[local].local_info()
{
continue;
}
}
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
local,
projection: place.projection.split_at(index + 1).0,
}) {
let var_index = field.index();
let upvar = self.upvars[var_index];
if let Some(hir_id) = upvar.info.capture_kind_expr_id {
let node = self.infcx.tcx.hir_node(hir_id);
if let hir::Node::Expr(expr) = node
&& let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
&& let hir::def::Res::Local(hir_id) = path.res
&& let hir::Node::Pat(pat) = self.infcx.tcx.hir_node(hir_id)
{
let name = upvar.to_string(self.infcx.tcx);
err.span_label(
pat.span,
format!("`{name}` declared here, outside the closure"),
);
break;
}
}
}
}
}
}
/// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
fn expected_fn_found_fn_mut_call(&self, err: &mut Diag<'_>, sp: Span, act: &str) {
err.span_label(sp, format!("cannot {act}"));
Expand All @@ -970,6 +1013,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let def_id = tcx.hir_enclosing_body_owner(fn_call_id);
let mut look_at_return = true;

err.span_label(closure_span, "in this closure");
// If the HIR node is a function or method call, get the DefId
// of the callee function or method, the span, and args of the call expr
let get_call_details = || {
Expand Down Expand Up @@ -1040,7 +1084,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
if let Some(span) = arg {
err.span_label(span, "change this to accept `FnMut` instead of `Fn`");
err.span_label(call_span, "expects `Fn` instead of `FnMut`");
err.span_label(closure_span, "in this closure");
look_at_return = false;
}
}
Expand All @@ -1067,7 +1110,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
sig.decl.output.span(),
"change this to return `FnMut` instead of `Fn`",
);
err.span_label(closure_span, "in this closure");
}
_ => {}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ fn instrument_function_attr<'ll>(
}

fn nojumptables_attr<'ll>(cx: &SimpleCx<'ll>, sess: &Session) -> Option<&'ll Attribute> {
if !sess.opts.unstable_opts.no_jump_tables {
if sess.opts.cg.jump_tables {
return None;
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html

// tidy-alphabetical-start
#![cfg_attr(bootstrap, feature(debug_closure_helpers))]
#![feature(associated_type_defaults)]
#![feature(closure_track_caller)]
#![feature(debug_closure_helpers)]
#![feature(exhaustive_patterns)]
#![feature(never_type)]
#![feature(variant_count)]
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ This API is completely unstable and subject to change.
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
#![cfg_attr(bootstrap, feature(debug_closure_helpers))]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(assert_matches)]
#![feature(debug_closure_helpers)]
#![feature(gen_blocks)]
#![feature(if_let_guard)]
#![feature(iter_intersperse)]
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,7 @@ fn test_codegen_options_tracking_hash() {
tracked!(force_frame_pointers, FramePointer::Always);
tracked!(force_unwind_tables, Some(true));
tracked!(instrument_coverage, InstrumentCoverage::Yes);
tracked!(jump_tables, false);
tracked!(link_dead_code, Some(true));
tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto);
tracked!(llvm_args, vec![String::from("1"), String::from("2")]);
Expand Down Expand Up @@ -831,7 +832,6 @@ fn test_unstable_options_tracking_hash() {
tracked!(mutable_noalias, false);
tracked!(next_solver, NextSolverConfig { coherence: true, globally: true });
tracked!(no_generate_arange_section, true);
tracked!(no_jump_tables, true);
tracked!(no_link, true);
tracked!(no_profiler_runtime, true);
tracked!(no_trait_vptr, true);
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2093,6 +2093,8 @@ options! {
"instrument the generated code to support LLVM source-based code coverage reports \
(note, the compiler build config must include `profiler = true`); \
implies `-C symbol-mangling-version=v0`"),
jump_tables: bool = (true, parse_bool, [TRACKED],
"allow jump table and lookup table generation from switch case lowering (default: yes)"),
link_arg: (/* redirected to link_args */) = ((), parse_string_push, [UNTRACKED],
"a single extra argument to append to the linker invocation (can be used several times)"),
link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
Expand Down Expand Up @@ -2475,8 +2477,6 @@ options! {
"omit DWARF address ranges that give faster lookups"),
no_implied_bounds_compat: bool = (false, parse_bool, [TRACKED],
"disable the compatibility version of the `implied_bounds_ty` query"),
no_jump_tables: bool = (false, parse_no_value, [TRACKED],
"disable the jump tables and lookup tables that can be generated from a switch case lowering"),
no_leak_check: bool = (false, parse_no_value, [UNTRACKED],
"disable the 'leak check' for subtyping; unsound, but useful for tests"),
no_link: bool = (false, parse_no_value, [TRACKED],
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_target/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![cfg_attr(bootstrap, feature(debug_closure_helpers))]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(debug_closure_helpers)]
#![feature(iter_intersperse)]
#![feature(rustdoc_internals)]
// tidy-alphabetical-end
Expand Down
2 changes: 1 addition & 1 deletion library/alloc/src/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ pub use core::fmt::{DebugAsHex, FormattingOptions, Sign};
pub use core::fmt::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::fmt::{Formatter, Result, Write};
#[unstable(feature = "debug_closure_helpers", issue = "117729")]
#[stable(feature = "fmt_from_fn", since = "CURRENT_RUSTC_VERSION")]
pub use core::fmt::{FromFn, from_fn};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::fmt::{LowerExp, UpperExp};
Expand Down
19 changes: 8 additions & 11 deletions library/core/src/fmt/builders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1210,13 +1210,12 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
}
}

/// Creates a type whose [`fmt::Debug`] and [`fmt::Display`] impls are provided with the function
/// `f`.
/// Creates a type whose [`fmt::Debug`] and [`fmt::Display`] impls are
/// forwarded to the provided closure.
///
/// # Examples
///
/// ```
/// #![feature(debug_closure_helpers)]
/// use std::fmt;
///
/// let value = 'a';
Expand All @@ -1227,21 +1226,19 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
/// assert_eq!(format!("{}", wrapped), "'a'");
/// assert_eq!(format!("{:?}", wrapped), "'a'");
/// ```
#[unstable(feature = "debug_closure_helpers", issue = "117729")]
#[stable(feature = "fmt_from_fn", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "returns a type implementing Debug and Display, which do not have any effects unless they are used"]
pub fn from_fn<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result>(f: F) -> FromFn<F> {
FromFn(f)
}

/// Implements [`fmt::Debug`] and [`fmt::Display`] using a function.
/// Implements [`fmt::Debug`] and [`fmt::Display`] via the provided closure.
///
/// Created with [`from_fn`].
#[unstable(feature = "debug_closure_helpers", issue = "117729")]
pub struct FromFn<F>(F)
where
F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result;
#[stable(feature = "fmt_from_fn", since = "CURRENT_RUSTC_VERSION")]
pub struct FromFn<F>(F);

#[unstable(feature = "debug_closure_helpers", issue = "117729")]
#[stable(feature = "fmt_from_fn", since = "CURRENT_RUSTC_VERSION")]
impl<F> fmt::Debug for FromFn<F>
where
F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result,
Expand All @@ -1251,7 +1248,7 @@ where
}
}

#[unstable(feature = "debug_closure_helpers", issue = "117729")]
#[stable(feature = "fmt_from_fn", since = "CURRENT_RUSTC_VERSION")]
impl<F> fmt::Display for FromFn<F>
where
F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result,
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub use num_buffer::{NumBuffer, NumBufferTrait};

#[stable(feature = "debug_builders", since = "1.2.0")]
pub use self::builders::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple};
#[unstable(feature = "debug_closure_helpers", issue = "117729")]
#[stable(feature = "fmt_from_fn", since = "CURRENT_RUSTC_VERSION")]
pub use self::builders::{FromFn, from_fn};

/// The type returned by formatter methods.
Expand Down
44 changes: 44 additions & 0 deletions library/core/src/task/wake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,28 @@ impl Waker {
pub fn vtable(&self) -> &'static RawWakerVTable {
self.waker.vtable
}

/// Constructs a `Waker` from a function pointer.
#[inline]
#[must_use]
#[unstable(feature = "waker_from_fn_ptr", issue = "148457")]
pub const fn from_fn_ptr(f: fn()) -> Self {
// SAFETY: Unsafe is used for transmutes, pointer came from `fn()` so it
// is sound to transmute it back to `fn()`.
static VTABLE: RawWakerVTable = unsafe {
RawWakerVTable::new(
|this| RawWaker::new(this, &VTABLE),
|this| transmute::<*const (), fn()>(this)(),
|this| transmute::<*const (), fn()>(this)(),
|_| {},
)
};
let raw = RawWaker::new(f as *const (), &VTABLE);

// SAFETY: `clone` is just a copy, `drop` is a no-op while `wake` and
// `wake_by_ref` just call the function pointer.
unsafe { Self::from_raw(raw) }
}
}

#[stable(feature = "futures_api", since = "1.36.0")]
Expand Down Expand Up @@ -879,6 +901,28 @@ impl LocalWaker {
pub fn vtable(&self) -> &'static RawWakerVTable {
self.waker.vtable
}

/// Constructs a `LocalWaker` from a function pointer.
#[inline]
#[must_use]
#[unstable(feature = "waker_from_fn_ptr", issue = "148457")]
pub const fn from_fn_ptr(f: fn()) -> Self {
// SAFETY: Unsafe is used for transmutes, pointer came from `fn()` so it
// is sound to transmute it back to `fn()`.
static VTABLE: RawWakerVTable = unsafe {
RawWakerVTable::new(
|this| RawWaker::new(this, &VTABLE),
|this| transmute::<*const (), fn()>(this)(),
|this| transmute::<*const (), fn()>(this)(),
|_| {},
)
};
let raw = RawWaker::new(f as *const (), &VTABLE);

// SAFETY: `clone` is just a copy, `drop` is a no-op while `wake` and
// `wake_by_ref` just call the function pointer.
unsafe { Self::from_raw(raw) }
}
}
#[unstable(feature = "local_waker", issue = "118959")]
impl Clone for LocalWaker {
Expand Down
5 changes: 2 additions & 3 deletions library/std/src/sys/net/connection/uefi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,11 @@ impl TcpStream {
}

pub fn write_vectored(&self, buf: &[IoSlice<'_>]) -> io::Result<usize> {
// FIXME: UEFI does support vectored write, so implement that.
crate::io::default_write_vectored(|b| self.write(b), buf)
self.inner.write_vectored(buf, self.write_timeout()?)
}

pub fn is_write_vectored(&self) -> bool {
false
true
}

pub fn peer_addr(&self) -> io::Result<SocketAddr> {
Expand Down
12 changes: 11 additions & 1 deletion library/std/src/sys/net/connection/uefi/tcp.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::tcp4;
use crate::io;
use crate::io::{self, IoSlice};
use crate::net::SocketAddr;
use crate::ptr::NonNull;
use crate::sys::{helpers, unsupported};
Expand Down Expand Up @@ -28,6 +28,16 @@ impl Tcp {
}
}

pub(crate) fn write_vectored(
&self,
buf: &[IoSlice<'_>],
timeout: Option<Duration>,
) -> io::Result<usize> {
match self {
Self::V4(client) => client.write_vectored(buf, timeout),
}
}

pub(crate) fn read(&self, buf: &mut [u8], timeout: Option<Duration>) -> io::Result<usize> {
match self {
Self::V4(client) => client.read(buf, timeout),
Expand Down
Loading
Loading