Update to rust 2024 edition

This bravely avoids changing expr to expr_2021 in macros, which seems
extremely unlikely to be silently breaking anything.

See: https://doc.rust-lang.org/edition-guide/rust-2024/macro-fragment-specifiers.html

I do not believe we have any macros where this is relevant

Part of #11990
This commit is contained in:
Henrik Hørlück Berg
2025-10-22 18:56:03 +02:00
committed by Johannes Altmanninger
parent b47b61ea08
commit 00784248db
21 changed files with 96 additions and 88 deletions

View File

@@ -5,7 +5,7 @@ members = ["crates/*"]
[workspace.package]
# To build revisions that use Corrosion (those before 2024-01), use CMake 3.19, Rustc 1.78 and Rustup 1.27.
rust-version = "1.85"
edition = "2021"
edition = "2024"
repository = "https://github.com/fish-shell/fish-shell"
[workspace.dependencies]

View File

@@ -37,7 +37,8 @@ fn main() {
// the source directory is the current working directory of the build script
rsconf::set_env_value("FISH_BUILD_VERSION", version);
std::env::set_var("FISH_BUILD_VERSION", version);
// safety: single-threaded code.
unsafe { std::env::set_var("FISH_BUILD_VERSION", version) };
// These are necessary if built with embedded functions,
// but only in release builds (because rust-embed in debug builds reads from the filesystem).
@@ -159,9 +160,9 @@ fn has_small_stack(_: &Target) -> bool {
{
use core::ffi;
extern "C" {
fn pthread_get_stacksize_np(thread: *const ffi::c_void) -> usize;
fn pthread_self() -> *const ffi::c_void;
unsafe extern "C" {
unsafe fn pthread_get_stacksize_np(thread: *const ffi::c_void) -> usize;
unsafe fn pthread_self() -> *const ffi::c_void;
}
// build.rs is executed on the main thread, so we are getting the main thread's stack size.

View File

@@ -2350,7 +2350,7 @@ fn populate_list<Contents, List>(&mut self, list: &mut List, exhaust_stream: boo
self.chomp_extras(list.kind());
// Now try parsing a node.
if let Some(node) = self.try_parse::<Contents>() {
match self.try_parse::<Contents>() { Some(node) => {
// #7201: Minimize reallocations of contents vector
// Empirically, 99.97% of cases are 16 elements or fewer,
// with 75% being empty, so this works out best.
@@ -2358,14 +2358,14 @@ fn populate_list<Contents, List>(&mut self, list: &mut List, exhaust_stream: boo
contents.reserve(16);
}
contents.push(node);
} else if exhaust_stream && self.peek_type(0) != ParseTokenType::terminate {
} _ => if exhaust_stream && self.peek_type(0) != ParseTokenType::terminate {
// We aren't allowed to stop. Produce an error and keep going.
self.consume_excess_token_generating_error()
} else {
// We either stop once we can't parse any more of this contents node, or we
// exhausted the stream as requested.
break;
}
}}
}
// Populate our list from our contents.

View File

@@ -96,15 +96,15 @@ pub fn bg(parser: &Parser, streams: &mut IoStreams, args: &mut [&wstr]) -> Built
// Non-existent jobs aren't an error, but information about them is useful.
let mut seen = HashSet::new();
for pid in pids {
if let Some((job_pos, job)) = parser.job_get_with_index_from_pid(pid) {
match parser.job_get_with_index_from_pid(pid) { Some((job_pos, job)) => {
if seen.insert(&*job as *const _) {
send_to_bg(parser, streams, cmd, job_pos)?;
}
} else {
} _ => {
streams
.err
.append(wgettext_fmt!("%s: Could not find job '%d'\n", cmd, pid));
}
}}
}
return Ok(SUCCESS);

View File

@@ -59,14 +59,14 @@ fn default() -> Self {
/// Return the internal_job_id for a pid, or None if none.
/// This looks through both active and finished jobs.
fn job_id_for_pid(pid: Pid, parser: &Parser) -> Option<u64> {
if let Some(job) = parser.job_get_from_pid(pid) {
match parser.job_get_from_pid(pid) { Some(job) => {
Some(job.internal_job_id)
} else {
} _ => {
parser
.get_wait_handles()
.get_by_pid(pid)
.map(|h| h.internal_job_id)
}
}}
}
/// Parses options to builtin function, populating opts.

View File

@@ -218,17 +218,17 @@ pub fn jobs(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> Bui
j = parser.job_get_from_pid(pid)
}
if let Some(j) = j.filter(|j| !j.is_completed() && j.is_constructed()) {
match j.filter(|j| !j.is_completed() && j.is_constructed()) { Some(j) => {
builtin_jobs_print(&j, mode, false, streams);
found = true;
} else {
} _ => {
if mode != JobsPrintMode::PrintNothing {
streams
.err
.append(wgettext_fmt!("%s: No suitable job: %s\n", cmd, arg));
}
return Err(STATUS_CMD_ERROR);
}
}}
}
} else {
for j in &parser.jobs()[..] {

View File

@@ -1855,7 +1855,7 @@ fn getpwent_name() -> Option<WString> {
fn apply_var_assignments<T: AsRef<wstr>>(
&mut self,
var_assignments: &[T],
) -> Option<ScopeGuard<(), impl FnOnce(()) + 'ctx>> {
) -> Option<ScopeGuard<(), impl FnOnce(()) + 'ctx + use<'ctx, T>>> {
if !self.ctx.has_parser() || var_assignments.is_empty() {
return None;
}

View File

@@ -585,8 +585,8 @@ fn export_array_needs_regeneration(&self) -> bool {
let mut cursor = self.export_array_generations.iter().fuse();
let mut mismatch = false;
self.enumerate_generations(|gen| {
if cursor.next().cloned() != Some(gen) {
self.enumerate_generations(|r#gen| {
if cursor.next().cloned() != Some(r#gen) {
mismatch = true;
}
});
@@ -657,7 +657,7 @@ pub fn export_array(&mut self) -> Arc<OwningNullTerminatedArray> {
// Have to pull this into a local to satisfy the borrow checker.
let mut generations = std::mem::take(&mut self.export_array_generations);
self.enumerate_generations(|gen| generations.push(gen));
self.enumerate_generations(|r#gen| generations.push(r#gen));
self.export_array_generations = generations;
}
return self.export_array.as_ref().unwrap().clone();

View File

@@ -148,8 +148,8 @@ fn handle_timezone(var_name: &wstr, vars: &EnvStack) {
unsetenv_lock(var_name);
}
extern "C" {
fn tzset();
unsafe extern "C" {
unsafe fn tzset();
}
unsafe {

View File

@@ -386,11 +386,11 @@ pub fn get_desc(parser: &Parser, evt: &Event) -> WString {
}
EventDescription::JobExit { pid, .. } => {
if let Some(pid) = pid {
if let Some(job) = parser.job_get_from_pid(*pid) {
match parser.job_get_from_pid(*pid) { Some(job) => {
format!("exit handler for job {}, '{}'", job.job_id(), job.command())
} else {
} _ => {
format!("exit handler for job with pid {pid}")
}
}}
} else {
"exit handler for any job".to_string()
}

View File

@@ -8,27 +8,27 @@
STATUS_INVALID_ARGS, STATUS_NOT_EXECUTABLE, STATUS_READ_TOO_MUCH, STATUS_UNMATCHED_WILDCARD,
};
use crate::common::{
EXPAND_RESERVED_BASE, EXPAND_RESERVED_END, EscapeFlags, EscapeStringStyle, UnescapeFlags,
UnescapeStringStyle, char_offset, charptr2wcstring, escape, escape_string,
escape_string_for_double_quotes, unescape_string, valid_var_name_char, wcs2zstring,
char_offset, charptr2wcstring, escape, escape_string, escape_string_for_double_quotes,
unescape_string, valid_var_name_char, wcs2zstring, EscapeFlags, EscapeStringStyle,
UnescapeFlags, UnescapeStringStyle, EXPAND_RESERVED_BASE, EXPAND_RESERVED_END,
};
use crate::complete::{CompleteFlags, Completion, CompletionList, CompletionReceiver};
use crate::env::{EnvVar, Environment};
use crate::exec::exec_subshell_for_expand;
use crate::future_feature_flags::{FeatureFlag, feature_test};
use crate::history::{History, history_session_id};
use crate::future_feature_flags::{feature_test, FeatureFlag};
use crate::history::{history_session_id, History};
use crate::operation_context::OperationContext;
use crate::parse_constants::{ParseError, ParseErrorCode, ParseErrorList, SOURCE_LOCATION_UNKNOWN};
use crate::parse_util::{
MaybeParentheses, parse_util_expand_variable_error, parse_util_locate_cmdsubst_range,
parse_util_expand_variable_error, parse_util_locate_cmdsubst_range, MaybeParentheses,
};
use crate::path::path_apply_working_directory;
use crate::util::wcsfilecmp_glob;
use crate::wchar::prelude::*;
use crate::wcstringutil::{join_strings, trim};
use crate::wildcard::{ANY_CHAR, ANY_STRING, ANY_STRING_RECURSIVE, WildcardResult};
use crate::wildcard::{wildcard_expand_string, wildcard_has_internal};
use crate::wutil::{Options, normalize_path, wcstoi_partial};
use crate::wildcard::{WildcardResult, ANY_CHAR, ANY_STRING, ANY_STRING_RECURSIVE};
use crate::wutil::{normalize_path, wcstoi_partial, Options};
use bitflags::bitflags;
use std::mem::MaybeUninit;
@@ -356,7 +356,7 @@ macro_rules! append_syntax_error {
$errors:expr, $source_start:expr,
$fmt:expr $(, $arg:expr )* $(,)?
) => {
if let Some(ref mut errors) = $errors {
if let Some(ref mut errors) = $errors.as_mut() {
let mut error = ParseError::default();
error.source_start = $source_start;
error.source_length = 0;
@@ -386,7 +386,7 @@ macro_rules! append_cmdsub_error_formatted {
$errors:expr, $source_start:expr, $source_end:expr,
$text:expr $(,)?
) => {
if let Some(ref mut errors) = $errors {
if let Some(ref mut errors) = $errors.as_mut() {
let mut error = ParseError::default();
error.source_start = $source_start;
error.source_length = $source_end - $source_start + 1;
@@ -404,7 +404,7 @@ fn append_overflow_error(
errors: &mut Option<&mut ParseErrorList>,
source_start: Option<usize>,
) -> ExpandResult {
if let Some(ref mut errors) = errors {
if let Some(errors) = errors {
errors.push(ParseError {
source_start: source_start.unwrap_or(SOURCE_LOCATION_UNKNOWN),
source_length: 0,
@@ -623,7 +623,7 @@ fn expand_variables(
// It's an error if the name is empty.
if var_name.is_empty() {
if let Some(ref mut errors) = errors {
if let Some(errors) = errors {
parse_util_expand_variable_error(
&instr,
0, /* global_token_pos */

View File

@@ -30,8 +30,8 @@
/// A safe wrapper around the system `wcwidth()` function
#[cfg(not(cygwin))]
pub fn wcwidth(c: char) -> isize {
extern "C" {
pub fn wcwidth(c: libc::wchar_t) -> libc::c_int;
unsafe extern "C" {
pub unsafe fn wcwidth(c: libc::wchar_t) -> libc::c_int;
}
const _: () = assert!(std::mem::size_of::<libc::wchar_t>() >= std::mem::size_of::<char>());

View File

@@ -10,18 +10,20 @@
/// Return the first character of a C string, or None if null, empty, has a length more than 1, or negative.
unsafe fn first_char(s: *const libc::c_char) -> Option<char> {
#[allow(unused_comparisons, clippy::absurd_extreme_comparisons)]
if !s.is_null() && *s > 0 && *s <= 127 && *s.offset(1) == 0 {
Some((*s as u8) as char)
} else {
None
unsafe {
#[allow(unused_comparisons, clippy::absurd_extreme_comparisons)]
if !s.is_null() && *s > 0 && *s <= 127 && *s.offset(1) == 0 {
Some((*s as u8) as char)
} else {
None
}
}
}
/// Convert a libc lconv to a Locale.
unsafe fn lconv_to_locale(lconv: &libc::lconv) -> Locale {
let decimal_point = first_char(lconv.decimal_point).unwrap_or('.');
let thousands_sep = first_char(lconv.thousands_sep);
let decimal_point = unsafe { first_char(lconv.decimal_point).unwrap_or('.') };
let thousands_sep = unsafe { first_char(lconv.thousands_sep) };
let empty = &[0 as libc::c_char];
// Up to 4 groups.
@@ -35,7 +37,7 @@ unsafe fn lconv_to_locale(lconv: &libc::lconv) -> Locale {
let mut last_group: u8 = 0;
let mut group_repeat = false;
for group in grouping.iter_mut() {
let gc = *group_cursor;
let gc = unsafe { *group_cursor };
if gc == 0 {
// Preserve last_group, do not advance cursor.
group_repeat = true;
@@ -46,7 +48,7 @@ unsafe fn lconv_to_locale(lconv: &libc::lconv) -> Locale {
} else {
// Record last group, advance cursor.
last_group = gc as u8;
group_cursor = group_cursor.offset(1);
group_cursor = unsafe { group_cursor.offset(1) };
}
*group = last_group;
}
@@ -61,8 +63,8 @@ unsafe fn lconv_to_locale(lconv: &libc::lconv) -> Locale {
/// Read the numeric locale, or None on any failure.
#[cfg(localeconv_l)]
unsafe fn read_locale() -> Option<Locale> {
extern "C" {
fn localeconv_l(loc: libc::locale_t) -> *const libc::lconv;
unsafe extern "C" {
unsafe fn localeconv_l(loc: libc::locale_t) -> *const libc::lconv;
}
const empty: [libc::c_char; 1] = [0];
@@ -70,19 +72,20 @@ unsafe fn read_locale() -> Option<Locale> {
// We create a new locale (pass 0 locale_t base)
// and pass no "locale", so everything else is taken from the environment.
// This is fine because we're only using this for numbers.
let loc = libc::newlocale(libc::LC_NUMERIC_MASK, empty.as_ptr(), 0 as libc::locale_t);
let loc =
unsafe { libc::newlocale(libc::LC_NUMERIC_MASK, empty.as_ptr(), 0 as libc::locale_t) };
if loc.is_null() {
return None;
}
let lconv = localeconv_l(loc);
let lconv = unsafe { localeconv_l(loc) };
let result = if lconv.is_null() {
None
} else {
Some(lconv_to_locale(&*lconv))
Some(unsafe { lconv_to_locale(&*lconv) })
};
libc::freelocale(loc);
unsafe { libc::freelocale(loc) };
result
}
@@ -94,16 +97,20 @@ unsafe fn read_locale() -> Option<Locale> {
const empty: [libc::c_char; 1] = [0];
const c_loc_str: [libc::c_char; 2] = [b'C' as libc::c_char, 0];
libc::setlocale(libc::LC_NUMERIC, empty.as_ptr());
unsafe {
libc::setlocale(libc::LC_NUMERIC, empty.as_ptr());
}
let lconv = libc::localeconv();
let lconv = unsafe { libc::localeconv() };
let result = if lconv.is_null() {
None
} else {
Some(lconv_to_locale(&*lconv))
Some(unsafe { lconv_to_locale(&*lconv) })
};
// Note we *always* use a C-locale for numbers, because we always want "." except for in printf.
libc::setlocale(libc::LC_NUMERIC, c_loc_str.as_ptr());
unsafe {
libc::setlocale(libc::LC_NUMERIC, c_loc_str.as_ptr());
}
result
}

View File

@@ -1368,7 +1368,7 @@ macro_rules! append_syntax_error_formatted {
$errors:expr, $source_location:expr,
$source_length:expr, $text:expr
) => {{
if let Some(ref mut errors) = $errors {
if let Some(ref mut errors) = $errors.as_mut() {
let mut error = ParseError::default();
error.source_start = $source_location;
error.source_length = $source_length;
@@ -1441,7 +1441,7 @@ pub fn parse_util_detect_errors_in_argument(
&& !valid_var_name_char(next_char)
{
err = ParserTestErrorBits::ERROR;
if let Some(ref mut out_errors) = out_errors {
if let Some(out_errors) = out_errors {
let mut first_dollar = idx;
while first_dollar > 0
&& [VARIABLE_EXPAND, VARIABLE_EXPAND_SINGLE]
@@ -1504,7 +1504,7 @@ pub fn parse_util_detect_errors_in_argument(
// within the string, and the offset of the node.
let error_offset = parens.start() + 1 + source_start;
parse_error_offset_source_start(&mut subst_errors, error_offset);
if let Some(ref mut out_errors) = out_errors {
if let Some(out_errors) = out_errors {
out_errors.extend(subst_errors);
}
@@ -1817,7 +1817,7 @@ fn detect_errors_in_decorated_statement(
}
}
if let Some(ref mut parse_errors) = parse_errors {
if let Some(parse_errors) = parse_errors {
// The expansion errors here go from the *command* onwards,
// so we need to offset them by the *command* offset,
// excluding the decoration.

View File

@@ -4844,7 +4844,7 @@ fn get_autosuggestion_performer(
command_line: WString,
cursor_pos: usize,
history: Arc<History>,
) -> impl FnOnce() -> AutosuggestionResult {
) -> impl FnOnce() -> AutosuggestionResult + use<> {
let generation_count = read_generation_count();
let vars = parser.vars().snapshot();
let working_directory = parser.vars().get_pwd_slash();
@@ -5207,7 +5207,7 @@ fn get_highlight_performer(
parser: &Parser,
el: &EditableLine,
io_ok: bool,
) -> impl FnOnce() -> HighlightResult {
) -> impl FnOnce() -> HighlightResult + use<> {
let vars = parser.vars().snapshot();
let generation_count = read_generation_count();
let position = el.position();
@@ -5794,8 +5794,8 @@ fn check_for_orphaned_process(loop_count: usize, shell_pgid: libc::pid_t) -> boo
// Try reading from the tty; if we get EIO we are orphaned. This is sort of bad because it
// may block.
if !we_think_we_are_orphaned && loop_count % 128 == 0 {
extern "C" {
fn ctermid(buf: *mut c_char) -> *mut c_char;
unsafe extern "C" {
unsafe fn ctermid(buf: *mut c_char) -> *mut c_char;
}
let tty = unsafe { ctermid(std::ptr::null_mut()) };
if tty.is_null() {

View File

@@ -310,13 +310,13 @@ pub fn signal_unblock_all() {
/// A Sigchecker can be used to check if a SIGINT (or SIGHUP) has been delivered.
pub struct SigChecker {
topic: Topic,
gen: Generation,
r#gen: Generation,
}
impl SigChecker {
/// Create a new checker for the given topic.
pub fn new(topic: Topic) -> Self {
let mut res = SigChecker { topic, gen: 0 };
let mut res = SigChecker { topic, r#gen: 0 };
// Call check() to update our generation.
res.check();
res
@@ -331,9 +331,9 @@ pub fn new_sighupint() -> Self {
/// was created.
pub fn check(&mut self) -> bool {
let tm = topic_monitor_principal();
let gen = tm.generation_for_topic(self.topic);
let changed = self.gen != gen;
self.gen = gen;
let r#gen = tm.generation_for_topic(self.topic);
let changed = self.r#gen != r#gen;
self.r#gen = r#gen;
changed
}
@@ -341,7 +341,7 @@ pub fn check(&mut self) -> bool {
pub fn wait(&self) {
let tm = topic_monitor_principal();
let gens = GenerationsList::invalid();
gens.set(self.topic, self.gen);
gens.set(self.topic, self.r#gen);
tm.check(&gens, true /* wait */);
}
}

View File

@@ -45,8 +45,8 @@ fn test_topic_monitor_torture() {
let t2 = Topic::sighupint;
let mut gens_list = vec![GenerationsList::invalid(); THREAD_COUNT];
let post_count = Arc::new(AtomicU64::new(0));
for gen in &mut gens_list {
*gen = monitor.current_generations();
for r#gen in &mut gens_list {
*r#gen = monitor.current_generations();
post_count.fetch_add(1, Ordering::Relaxed);
monitor.post(t1);
}

View File

@@ -585,16 +585,16 @@ pub fn new(timeout: Duration) -> Self {
fn run_next(&self, token: NonZeroU64) -> bool {
let request = {
let mut data = self.data.lock().expect("Mutex poisoned!");
if let Some(req) = data.next_req.take() {
match data.next_req.take() { Some(req) => {
data.start_time = Instant::now();
req
} else {
} _ => {
// There is no pending request. Mark this token as no longer running.
if Some(token) == data.active_token {
data.active_token = None;
}
return false;
}
}}
};
// Execute request after unlocking the mutex.

View File

@@ -90,14 +90,14 @@ pub fn invalid() -> GenerationsList {
#[allow(dead_code)]
fn describe(&self) -> WString {
let mut result = WString::new();
for gen in self.as_array() {
for r#gen in self.as_array() {
if !result.is_empty() {
result.push(',');
}
if gen == INVALID_GENERATION {
if r#gen == INVALID_GENERATION {
result.push_str("-1");
} else {
result.push_str(&gen.to_string());
result.push_str(&r#gen.to_string());
}
}
return result;
@@ -145,8 +145,8 @@ pub fn is_valid(&self, topic: Topic) -> bool {
/// Return whether any topic is valid.
pub fn any_valid(&self) -> bool {
let mut valid = false;
for gen in self.as_array() {
if gen != INVALID_GENERATION {
for r#gen in self.as_array() {
if r#gen != INVALID_GENERATION {
valid = true;
}
}

View File

@@ -7,17 +7,17 @@
use std::ffi::CString;
use std::os::fd::{BorrowedFd, RawFd};
extern "C" {
fn notify_register_file_descriptor(
unsafe extern "C" {
unsafe fn notify_register_file_descriptor(
name: *const c_char,
fd: *mut c_int,
flags: c_int,
token: *mut c_int,
) -> u32;
fn notify_post(name: *const c_char) -> u32;
unsafe fn notify_post(name: *const c_char) -> u32;
fn notify_cancel(token: c_int) -> c_int;
unsafe fn notify_cancel(token: c_int) -> c_int;
}
const NOTIFY_STATUS_OK: u32 = 0;

View File

@@ -72,7 +72,7 @@ fn test_wwrite_to_fd() {
assert!(fd.is_valid());
let mut input = WString::new();
for _i in 0..size {
input.push(rng.gen());
input.push(rng.r#gen());
}
let amt = wwrite_to_fd(&input, fd.fd()).unwrap();