diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index 21f6d7e96f..44df116139 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -39,7 +39,7 @@ build-system-ubuntu: - job: amd64-ubuntu2204-container variables: IMAGE: ubuntu2204 - CONFIGURE_ARGS: --enable-docs + CONFIGURE_ARGS: --enable-docs --enable-rust TARGETS: alpha-softmmu microblazeel-softmmu mips64el-softmmu MAKE_CHECK_ARGS: check-build diff --git a/docs/about/build-platforms.rst b/docs/about/build-platforms.rst index fc2743658d..e95784cdb5 100644 --- a/docs/about/build-platforms.rst +++ b/docs/about/build-platforms.rst @@ -117,14 +117,14 @@ Rust build dependencies a newer version using ``cargo install bindgen-cli``. QEMU requires Rust 1.83.0. This is available on all supported platforms - with two exception: Ubuntu LTS releases 22.04 and 24.04, and the - ``mips64el`` architecture on Debian bookworm. For all other + except for the ``mips64el`` architecture on Debian bookworm. For all other architectures, Debian bookworm provides a new-enough Rust compiler in the ``rustc-web`` package. - It is expected that in the future Ubuntu will provide updated packages - like the existing ``rustc-1.82`` package. The path to ``rustc`` and - ``rustdoc`` will have to be provided manually to the configure script. + For Ubuntu 22.04 ("Jammy") and 24.04 ("Noble") updated versions of + Rust are available through packages such as ``rustc-1.83`` package; + the path to ``rustc`` and ``rustdoc`` has to be provided manually to + the configure script. Some distros prefer to avoid vendored crate sources, and instead use local sources from e.g. ``/usr/share/cargo/registry``. QEMU includes a diff --git a/rust/chardev/meson.build b/rust/chardev/meson.build index d365d8dd0f..36ada7c454 100644 --- a/rust/chardev/meson.build +++ b/rust/chardev/meson.build @@ -39,4 +39,4 @@ _chardev_rs = static_library( dependencies: [glib_sys_rs, common_rs, qemu_macros], ) -chardev_rs = declare_dependency(link_with: [_chardev_rs], dependencies: [chardev, qemuutil]) +chardev_rs = declare_dependency(link_with: [_chardev_rs], dependencies: [chardev]) diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs index 5e9b13fdf9..04155dabe1 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -17,7 +17,7 @@ use migration::{ }; use qom::{prelude::*, ObjectImpl, Owned, ParentField, ParentInit}; use system::{hwaddr, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder}; -use util::{log::Log, log_mask_ln}; +use util::{log::Log, log_mask_ln, ResultExt}; use crate::registers::{self, Interrupt, RegisterOffset}; @@ -697,7 +697,7 @@ pub unsafe extern "C" fn pl011_create( let chr = unsafe { Owned::::from(&*chr) }; dev.prop_set_chr("chardev", &chr); } - dev.sysbus_realize(); + dev.sysbus_realize().unwrap_fatal(); dev.mmio_map(0, addr); dev.connect_irq(0, &irq); diff --git a/rust/hw/core/src/sysbus.rs b/rust/hw/core/src/sysbus.rs index 282315fce9..68165e8929 100644 --- a/rust/hw/core/src/sysbus.rs +++ b/rust/hw/core/src/sysbus.rs @@ -4,12 +4,13 @@ //! Bindings to access `sysbus` functionality from Rust. -use std::{ffi::CStr, ptr::addr_of_mut}; +use std::ffi::CStr; pub use bindings::SysBusDeviceClass; use common::Opaque; use qom::{prelude::*, Owned}; use system::MemoryRegion; +use util::{Error, Result}; use crate::{ bindings, @@ -107,14 +108,12 @@ where } } - fn sysbus_realize(&self) { - // TODO: return an Error + fn sysbus_realize(&self) -> Result<()> { assert!(bql::is_locked()); unsafe { - bindings::sysbus_realize( - self.upcast().as_mut_ptr(), - addr_of_mut!(util::bindings::error_fatal), - ); + Error::with_errp(|errp| { + bindings::sysbus_realize(self.upcast().as_mut_ptr(), errp); + }) } } } diff --git a/rust/hw/timer/hpet/src/device.rs b/rust/hw/timer/hpet/src/device.rs index 23f2eefd1c..3564aa79c6 100644 --- a/rust/hw/timer/hpet/src/device.rs +++ b/rust/hw/timer/hpet/src/device.rs @@ -25,7 +25,10 @@ use system::{ bindings::{address_space_memory, address_space_stl_le, hwaddr}, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder, MEMTXATTRS_UNSPECIFIED, }; -use util::timer::{Timer, CLOCK_VIRTUAL, NANOSECONDS_PER_SECOND}; +use util::{ + ensure, + timer::{Timer, CLOCK_VIRTUAL, NANOSECONDS_PER_SECOND}, +}; use crate::fw_cfg::HPETFwConfig; @@ -728,14 +731,14 @@ impl HPETState { } fn realize(&self) -> util::Result<()> { - if self.num_timers < HPET_MIN_TIMERS || self.num_timers > HPET_MAX_TIMERS { - Err(format!( - "hpet.num_timers must be between {HPET_MIN_TIMERS} and {HPET_MAX_TIMERS}" - ))?; - } - if self.int_route_cap == 0 { - Err("hpet.hpet-intcap property not initialized")?; - } + ensure!( + (HPET_MIN_TIMERS..=HPET_MAX_TIMERS).contains(&self.num_timers), + "hpet.num_timers must be between {HPET_MIN_TIMERS} and {HPET_MAX_TIMERS}" + ); + ensure!( + self.int_route_cap != 0, + "hpet.hpet-intcap property not initialized" + ); self.hpet_id.set(HPETFwConfig::assign_hpet_id()?); diff --git a/rust/hw/timer/hpet/src/fw_cfg.rs b/rust/hw/timer/hpet/src/fw_cfg.rs index bb4ea8909a..777fc8ef45 100644 --- a/rust/hw/timer/hpet/src/fw_cfg.rs +++ b/rust/hw/timer/hpet/src/fw_cfg.rs @@ -5,6 +5,7 @@ use std::ptr::addr_of_mut; use common::Zeroable; +use util::{self, ensure}; /// Each `HPETState` represents a Event Timer Block. The v1 spec supports /// up to 8 blocks. QEMU only uses 1 block (in PC machine). @@ -36,7 +37,7 @@ pub static mut hpet_fw_cfg: HPETFwConfig = HPETFwConfig { }; impl HPETFwConfig { - pub(crate) fn assign_hpet_id() -> Result { + pub(crate) fn assign_hpet_id() -> util::Result { assert!(bql::is_locked()); // SAFETY: all accesses go through these methods, which guarantee // that the accesses are protected by the BQL. @@ -47,9 +48,7 @@ impl HPETFwConfig { fw_cfg.count = 0; } - if fw_cfg.count == 8 { - Err("Only 8 instances of HPET are allowed")?; - } + ensure!(fw_cfg.count != 8, "Only 8 instances of HPET are allowed"); let id: usize = fw_cfg.count.into(); fw_cfg.count += 1; diff --git a/rust/migration/src/vmstate.rs b/rust/migration/src/vmstate.rs index 5a237c409a..267f9c8e05 100644 --- a/rust/migration/src/vmstate.rs +++ b/rust/migration/src/vmstate.rs @@ -141,24 +141,24 @@ pub const fn vmstate_varray_flag(_: PhantomData) -> VMStateFlags /// [`Owned`]: ../../qom/qom/struct.Owned.html #[macro_export] macro_rules! vmstate_of { - ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])? $(, $test_fn:expr)? $(,)?) => { + ($struct_name:ty, $($field_name:ident).+ $([0 .. $($num:ident).+ $(* $factor:expr)?])? $(, $test_fn:expr)? $(,)?) => { $crate::bindings::VMStateField { - name: ::core::concat!(::core::stringify!($field_name), "\0") + name: ::core::concat!(::core::stringify!($($field_name).+), "\0") .as_bytes() .as_ptr().cast::<::std::os::raw::c_char>(), - offset: ::std::mem::offset_of!($struct_name, $field_name), - $(num_offset: ::std::mem::offset_of!($struct_name, $num),)? + offset: ::std::mem::offset_of!($struct_name, $($field_name).+), + $(num_offset: ::std::mem::offset_of!($struct_name, $($num).+),)? $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)? // The calls to `call_func_with_field!` are the magic that // computes most of the VMStateField from the type of the field. ..$crate::call_func_with_field!( $crate::vmstate::vmstate_base, $struct_name, - $field_name + $($field_name).+ )$(.with_varray_flag($crate::call_func_with_field!( $crate::vmstate::vmstate_varray_flag, $struct_name, - $num)) + $($num).+)) $(.with_varray_multiply($factor))?)? } }; diff --git a/rust/util/meson.build b/rust/util/meson.build index b0b75e93ff..8ad344dccb 100644 --- a/rust/util/meson.build +++ b/rust/util/meson.build @@ -43,7 +43,7 @@ _util_rs = static_library( dependencies: [anyhow_rs, libc_rs, foreign_rs, glib_sys_rs, common_rs, qom, qemuutil], ) -util_rs = declare_dependency(link_with: [_util_rs], dependencies: [qemuutil, qom]) +util_rs = declare_dependency(link_with: [_util_rs]) rust.test('rust-util-tests', _util_rs, dependencies: [qemuutil, qom], diff --git a/rust/util/src/error.rs b/rust/util/src/error.rs index bfa5a8685b..4edceff42f 100644 --- a/rust/util/src/error.rs +++ b/rust/util/src/error.rs @@ -14,8 +14,7 @@ //! [`ptr_or_propagate`](crate::Error::ptr_or_propagate) can be used to build //! a C return value while also propagating an error condition //! -//! * [`err_or_else`](crate::Error::err_or_else) and -//! [`err_or_unit`](crate::Error::err_or_unit) can be used to build a `Result` +//! * [`with_errp`](crate::Error::with_errp) can be used to build a `Result` //! //! This module is most commonly used at the boundary between C and Rust code; //! other code will usually access it through the @@ -38,7 +37,9 @@ use std::{ borrow::Cow, ffi::{c_char, c_int, c_void, CStr}, fmt::{self, Display}, - panic, ptr, + ops::Deref, + panic, + ptr::{self, addr_of_mut}, }; use foreign::{prelude::*, OwnedPointer}; @@ -49,94 +50,85 @@ pub type Result = std::result::Result; #[derive(Debug)] pub struct Error { - msg: Option>, - /// Appends the print string of the error to the msg if not None - cause: Option, + cause: anyhow::Error, file: &'static str, line: u32, } -impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - self.cause.as_ref().map(AsRef::as_ref) - } +impl Deref for Error { + type Target = anyhow::Error; - #[allow(deprecated)] - fn description(&self) -> &str { - self.msg - .as_deref() - .or_else(|| self.cause.as_deref().map(std::error::Error::description)) - .expect("no message nor cause?") + fn deref(&self) -> &Self::Target { + &self.cause } } impl Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut prefix = ""; - if let Some(ref msg) = self.msg { - write!(f, "{msg}")?; - prefix = ": "; - } - if let Some(ref cause) = self.cause { - write!(f, "{prefix}{cause}")?; - } else if prefix.is_empty() { - panic!("no message nor cause?"); - } - Ok(()) + Display::fmt(&format_args!("{:#}", self.cause), f) } } -impl From for Error { +impl From for Error +where + anyhow::Error: From, +{ #[track_caller] - fn from(msg: String) -> Self { - let location = panic::Location::caller(); - Error { - msg: Some(Cow::Owned(msg)), - cause: None, - file: location.file(), - line: location.line(), - } - } -} - -impl From<&'static str> for Error { - #[track_caller] - fn from(msg: &'static str) -> Self { - let location = panic::Location::caller(); - Error { - msg: Some(Cow::Borrowed(msg)), - cause: None, - file: location.file(), - line: location.line(), - } - } -} - -impl From for Error { - #[track_caller] - fn from(error: anyhow::Error) -> Self { - let location = panic::Location::caller(); - Error { - msg: None, - cause: Some(error), - file: location.file(), - line: location.line(), - } + fn from(src: E) -> Self { + Self::new(anyhow::Error::from(src)) } } impl Error { + /// Create a new error from an [`anyhow::Error`]. + /// + /// This wraps the error with QEMU's location tracking information. + /// Most code should use the `?` operator instead of calling this directly. + #[track_caller] + pub fn new(cause: anyhow::Error) -> Self { + let location = panic::Location::caller(); + Self { + cause, + file: location.file(), + line: location.line(), + } + } + + /// Create a new error from a string message. + /// + /// This is a convenience wrapper around [`Error::new`] for simple string + /// errors. Most code should use the [`ensure!`](crate::ensure) macro + /// instead of calling this directly. + #[track_caller] + pub fn msg(src: impl Into>) -> Self { + Self::new(anyhow::Error::msg(src.into())) + } + + #[track_caller] + #[doc(hidden)] + #[inline(always)] + pub fn format(args: fmt::Arguments) -> Self { + // anyhow::Error::msg will allocate anyway, might as well let fmt::format doit. + let msg = fmt::format(args); + Self::new(anyhow::Error::msg(msg)) + } + /// Create a new error, prepending `msg` to the /// description of `cause` #[track_caller] pub fn with_error(msg: impl Into>, cause: impl Into) -> Self { - let location = panic::Location::caller(); - Error { - msg: Some(msg.into()), - cause: Some(cause.into()), - file: location.file(), - line: location.line(), + fn do_with_error( + msg: Cow<'static, str>, + cause: anyhow::Error, + location: &'static panic::Location<'static>, + ) -> Error { + Error { + cause: cause.context(msg), + file: location.file(), + line: location.line(), + } } + do_with_error(msg.into(), cause.into(), panic::Location::caller()) } /// Consume a result, returning `false` if it is an error and @@ -221,39 +213,53 @@ impl Error { } } - /// Convert a C `Error*` into a Rust `Result`, using - /// `Ok(())` if `c_error` is NULL. Free the `Error*`. + /// Pass a C `Error*` to the closure, and convert the result + /// (either the return value of the closure, or the error) + /// into a Rust `Result`. /// /// # Safety /// - /// `c_error` must be `NULL` or valid; typically it was initialized - /// with `ptr::null_mut()` and passed by reference to a C function. - pub unsafe fn err_or_unit(c_error: *mut bindings::Error) -> Result<()> { - // SAFETY: caller guarantees c_error is valid - unsafe { Self::err_or_else(c_error, || ()) } - } + /// One exit from `f`, `c_error` must be unchanged or point to a + /// valid C [`struct Error`](bindings::Error). + pub unsafe fn with_errp T>(f: F) -> Result { + let mut c_error: *mut bindings::Error = ptr::null_mut(); - /// Convert a C `Error*` into a Rust `Result`, calling `f()` to - /// obtain an `Ok` value if `c_error` is NULL. Free the `Error*`. - /// - /// # Safety - /// - /// `c_error` must be `NULL` or point to a valid C [`struct - /// Error`](bindings::Error); typically it was initialized with - /// `ptr::null_mut()` and passed by reference to a C function. - pub unsafe fn err_or_else T>( - c_error: *mut bindings::Error, - f: F, - ) -> Result { - // SAFETY: caller guarantees c_error is valid - let err = unsafe { Option::::from_foreign(c_error) }; - match err { - None => Ok(f()), - Some(err) => Err(err), + // SAFETY: guaranteed by the postcondition of `f` + match (f(&mut c_error), unsafe { c_error.into_native() }) { + (result, None) => Ok(result), + (_, Some(err)) => Err(err), } } } +/// Extension trait for `std::result::Result`, providing extra +/// methods when the error type can be converted into a QEMU +/// Error. +pub trait ResultExt { + /// The success type `T` in `Result`. + type OkType; + + /// Report a fatal error and exit QEMU, or return the success value. + /// Note that, unlike [`unwrap()`](std::result::Result::unwrap), this + /// is not an abort and can be used for user errors. + fn unwrap_fatal(self) -> Self::OkType; +} + +impl ResultExt for std::result::Result +where + Error: From, +{ + type OkType = T; + + fn unwrap_fatal(self) -> T { + // SAFETY: errp is valid + self.map_err(|err| unsafe { + Error::from(err).propagate(addr_of_mut!(bindings::error_fatal)) + }) + .unwrap() + } +} + impl FreeForeign for Error { type Foreign = bindings::Error; @@ -302,8 +308,7 @@ impl FromForeign for Error { }; Error { - msg: FromForeign::cloned_from_foreign(error.msg), - cause: None, + cause: anyhow::Error::msg(String::cloned_from_foreign(error.msg)), file: file.unwrap(), line: error.line as u32, } @@ -311,6 +316,53 @@ impl FromForeign for Error { } } +/// Ensure that a condition is true, returning an error if it is false. +/// +/// This macro is similar to [`anyhow::ensure`] but returns a QEMU [`Result`]. +/// If the condition evaluates to `false`, the macro returns early with an error +/// constructed from the provided message. +/// +/// # Examples +/// +/// ``` +/// # use util::{ensure, Result}; +/// # fn check_positive(x: i32) -> Result<()> { +/// ensure!(x > 0, "value must be positive"); +/// # Ok(()) +/// # } +/// ``` +/// +/// ``` +/// # use util::{ensure, Result}; +/// # const MIN: i32 = 123; +/// # const MAX: i32 = 456; +/// # fn check_range(x: i32) -> Result<()> { +/// ensure!( +/// x >= MIN && x <= MAX, +/// "{} not between {} and {}", +/// x, +/// MIN, +/// MAX +/// ); +/// # Ok(()) +/// # } +/// ``` +#[macro_export] +macro_rules! ensure { + ($cond:expr, $fmt:literal, $($arg:tt)*) => { + if !$cond { + let e = $crate::Error::format(format_args!($fmt, $($arg)*)); + return $crate::Result::Err(e); + } + }; + ($cond:expr, $err:expr $(,)?) => { + if !$cond { + let e = $crate::Error::msg($err); + return $crate::Result::Err(e); + } + }; +} + #[cfg(test)] mod tests { use std::ffi::CStr; @@ -345,19 +397,10 @@ mod tests { unsafe { CStr::from_ptr(bindings::error_get_pretty(local_err)) } } - #[test] - #[allow(deprecated)] - fn test_description() { - use std::error::Error; - - assert_eq!(super::Error::from("msg").description(), "msg"); - assert_eq!(super::Error::from("msg".to_owned()).description(), "msg"); - } - #[test] fn test_display() { - assert_eq!(&*format!("{}", Error::from("msg")), "msg"); - assert_eq!(&*format!("{}", Error::from("msg".to_owned())), "msg"); + assert_eq!(&*format!("{}", Error::msg("msg")), "msg"); + assert_eq!(&*format!("{}", Error::msg("msg".to_owned())), "msg"); assert_eq!(&*format!("{}", Error::from(anyhow!("msg"))), "msg"); assert_eq!( @@ -374,7 +417,7 @@ mod tests { assert!(Error::bool_or_propagate(Ok(()), &mut local_err)); assert_eq!(local_err, ptr::null_mut()); - let my_err = Error::from("msg"); + let my_err = Error::msg("msg"); assert!(!Error::bool_or_propagate(Err(my_err), &mut local_err)); assert_ne!(local_err, ptr::null_mut()); assert_eq!(error_get_pretty(local_err), c"msg"); @@ -391,7 +434,7 @@ mod tests { assert_eq!(String::from_foreign(ret), "abc"); assert_eq!(local_err, ptr::null_mut()); - let my_err = Error::from("msg"); + let my_err = Error::msg("msg"); assert_eq!( Error::ptr_or_propagate(Err::(my_err), &mut local_err), ptr::null_mut() @@ -403,13 +446,16 @@ mod tests { } #[test] - fn test_err_or_unit() { + fn test_with_errp() { unsafe { - let result = Error::err_or_unit(ptr::null_mut()); - assert_match!(result, Ok(())); + let result = Error::with_errp(|_errp| true); + assert_match!(result, Ok(true)); - let err = error_for_test(c"msg"); - let err = Error::err_or_unit(err.into_inner()).unwrap_err(); + let err = Error::with_errp(|errp| { + *errp = error_for_test(c"msg").into_inner(); + false + }) + .unwrap_err(); assert_eq!(&*format!("{err}"), "msg"); } } diff --git a/rust/util/src/lib.rs b/rust/util/src/lib.rs index 16c89b9517..d14aa14ca7 100644 --- a/rust/util/src/lib.rs +++ b/rust/util/src/lib.rs @@ -6,4 +6,4 @@ pub mod log; pub mod module; pub mod timer; -pub use error::{Error, Result}; +pub use error::{Error, Result, ResultExt}; diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index d3d75f3f13..d0f4537f25 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1741,13 +1741,7 @@ sub process { } } elsif ($line =~ /^\+\+\+\s+(\S+)/) { $realfile = $1; - $realfile =~ s@^([^/]*)/@@ if (!$file); - - $p1_prefix = $1; - if (!$file && $tree && $p1_prefix ne '' && - -e "$root/$p1_prefix") { - WARN("patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n"); - } + $realfile =~ s@^[^/]*/@@ if (!$file); if (defined $fileinfo && !$fileinfo->{isgit}) { $fileinfo->{lineend} = $oldhere; diff --git a/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml b/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml index 70063db198..d303411391 100644 --- a/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml +++ b/scripts/ci/setup/ubuntu/ubuntu-2404-aarch64.yaml @@ -119,7 +119,7 @@ packages: - python3-wheel - python3-yaml - rpm2cpio - - rustc-1.77 + - rustc-1.83 - sed - socat - sparse diff --git a/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml b/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml index 4f1a49be34..4ee8630cc4 100644 --- a/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml +++ b/scripts/ci/setup/ubuntu/ubuntu-2404-s390x.yaml @@ -117,7 +117,7 @@ packages: - python3-wheel - python3-yaml - rpm2cpio - - rustc-1.77 + - rustc-1.83 - sed - socat - sparse diff --git a/tests/docker/dockerfiles/ubuntu2204.docker b/tests/docker/dockerfiles/ubuntu2204.docker index b393db55a8..602d419624 100644 --- a/tests/docker/dockerfiles/ubuntu2204.docker +++ b/tests/docker/dockerfiles/ubuntu2204.docker @@ -124,7 +124,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ python3-wheel \ python3-yaml \ rpm2cpio \ - rustc-1.77 \ + rustc-1.83 \ sed \ socat \ sparse \ @@ -155,8 +155,8 @@ ENV LANG "en_US.UTF-8" ENV MAKE "/usr/bin/make" ENV NINJA "/usr/bin/ninja" ENV PYTHON "/usr/bin/python3" -ENV RUSTC=/usr/bin/rustc-1.77 -ENV RUSTDOC=/usr/bin/rustdoc-1.77 +ENV RUSTC=/usr/bin/rustc-1.83 +ENV RUSTDOC=/usr/bin/rustdoc-1.83 ENV CARGO_HOME=/usr/local/cargo ENV PATH=$CARGO_HOME/bin:$PATH RUN DEBIAN_FRONTEND=noninteractive eatmydata \ diff --git a/tests/lcitool/mappings.yml b/tests/lcitool/mappings.yml index 8f0e95e1c5..a749cf8c51 100644 --- a/tests/lcitool/mappings.yml +++ b/tests/lcitool/mappings.yml @@ -70,8 +70,8 @@ mappings: rust: Debian12: rustc-web - Ubuntu2204: rustc-1.77 - Ubuntu2404: rustc-1.77 + Ubuntu2204: rustc-1.83 + Ubuntu2404: rustc-1.83 pypi_mappings: # Request more recent version diff --git a/tests/lcitool/refresh b/tests/lcitool/refresh index 7fbdf6f340..df186caffe 100755 --- a/tests/lcitool/refresh +++ b/tests/lcitool/refresh @@ -152,8 +152,8 @@ fedora_rustup_nightly_extras = [ ] ubuntu2204_rust_extras = [ - "ENV RUSTC=/usr/bin/rustc-1.77\n", - "ENV RUSTDOC=/usr/bin/rustdoc-1.77\n", + "ENV RUSTC=/usr/bin/rustc-1.83\n", + "ENV RUSTDOC=/usr/bin/rustdoc-1.83\n", "ENV CARGO_HOME=/usr/local/cargo\n", 'ENV PATH=$CARGO_HOME/bin:$PATH\n', "RUN DEBIAN_FRONTEND=noninteractive eatmydata \\\n",