You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by gi...@apache.org on 2026/10/02 09:08:12 UTC
(datafusion) 01/01: chore: Upgrade to Rust 1.99, MSRV to 1.95 (#25935)
This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-25935-4d167a167228a424ef8cc29fd6bea5f17fc23c2a
in repository https://gitbox.apache.org/repos/asf/datafusion.git
commit c297f83cb107b9546b23aba154be67ef88662b72
Author: Neil Conway <ne...@gmail.com>
AuthorDate: Fri Oct 2 09:07:44 2026 +0000
chore: Upgrade to Rust 1.99, MSRV to 1.95 (#25935)
## Which issue does this PR close?
- N/A
## Rationale for this change
Update the Rust toolchain version to 1.99, and the MSRV to Rust 1.95.
The MSRV bump is because 1.99 deprecates `AtomicUsize::fetch_update` in
favour of `AtomicUsize::try_update`, but the latter was only stabilized
in Rust 1.95.
Rust 1.99 moves from LLVM 22.1.8 to LLVM 23.1.1. I haven't attempted to
validate how that impacts codegen.
## What changes are included in this PR?
* Fix various new clippy warnings
* Add migration guide note for MSRV bump
## What is the testing strategy for this PR?
Existing tests pass.
## Are there any user-facing changes?
Yes, MSRV bump.
---
Cargo.toml | 3 ++-
datafusion/common/src/param_value.rs | 3 +--
datafusion/core/benches/data_utils/mod.rs | 2 +-
datafusion/core/tests/datasource/object_store_access.rs | 6 +-----
.../tests/memory_limit/memory_limit_validation/utils.rs | 10 +---------
datafusion/datasource-parquet/src/source.rs | 3 +--
datafusion/datasource/src/mod.rs | 2 +-
datafusion/execution/src/memory_pool/mod.rs | 6 +++---
datafusion/execution/src/memory_pool/pool.rs | 2 +-
datafusion/expr/src/lib.rs | 2 +-
datafusion/expr/src/proto.rs | 3 +--
datafusion/functions-aggregate/src/first_last.rs | 15 +++++----------
datafusion/functions/src/core/getfield.rs | 13 ++++---------
datafusion/physical-plan/src/coalesce_batches.rs | 4 +---
datafusion/physical-plan/src/repartition/mod.rs | 3 +--
.../physical-plan/src/sorts/sort_preserving_merge.rs | 5 +----
datafusion/physical-plan/src/streaming.rs | 5 +----
datafusion/physical-plan/src/topk/mod.rs | 2 +-
.../substrait/src/logical_plan/consumer/rel/fetch_rel.rs | 4 ++++
.../substrait/src/logical_plan/consumer/rel/filter_rel.rs | 4 ++++
datafusion/substrait/src/logical_plan/consumer/rel/mod.rs | 4 ++++
.../src/logical_plan/consumer/rel/project_rel.rs | 4 ++++
datafusion/substrait/src/physical_plan/consumer.rs | 4 ++++
dev/depcheck/rust-toolchain.toml | 2 +-
docs/source/contributor-guide/development_environment.md | 2 +-
docs/source/library-user-guide/upgrading/56.0.0.md | 6 ++++++
rust-toolchain.toml | 2 +-
27 files changed, 57 insertions(+), 64 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
index 8da1274aa9..7bbfe851fd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -79,7 +79,7 @@ license = "Apache-2.0"
readme = "README.md"
repository = "https://github.com/apache/datafusion"
# Define Minimum Supported Rust Version (MSRV)
-rust-version = "1.94.0"
+rust-version = "1.95.0"
# Define DataFusion version
version = "55.1.0"
@@ -273,6 +273,7 @@ wildcard_dependencies = "warn"
# Pedantic lints we opt out of, with the number of hits at the time we enabled `pedantic`.
# Some of these we should consider enabling.
+assert_is_empty = "allow" # 105 hits
cast_lossless = "allow" # 361 hits
cast_possible_truncation = "allow" # 911 hits
cast_possible_wrap = "allow" # 493 hits
diff --git a/datafusion/common/src/param_value.rs b/datafusion/common/src/param_value.rs
index 1979daa7e3..c228dd451a 100644
--- a/datafusion/common/src/param_value.rs
+++ b/datafusion/common/src/param_value.rs
@@ -71,14 +71,13 @@ impl ParamValues {
&format!(" at index {i}"),
)?;
}
- Ok(())
}
ParamValues::Map(_) => {
// If it is a named query, variables can be reused,
// but the lengths are not necessarily equal
- Ok(())
}
}
+ Ok(())
}
pub fn get_placeholders_with_values(&self, id: &str) -> Result<ScalarAndMetadata> {
diff --git a/datafusion/core/benches/data_utils/mod.rs b/datafusion/core/benches/data_utils/mod.rs
index 728c6490c7..992ef0b47a 100644
--- a/datafusion/core/benches/data_utils/mod.rs
+++ b/datafusion/core/benches/data_utils/mod.rs
@@ -233,7 +233,7 @@ pub(crate) fn make_data(
})
};
let gen_sample_cnt =
- |mut rng: &mut rand::rngs::SmallRng| pareto.sample(&mut rng).ceil() as u32;
+ |rng: &mut rand::rngs::SmallRng| pareto.sample(rng).ceil() as u32;
let mut group_ids = (0..simultaneous_group_cnt)
.map(|_| gen_id(&mut rng))
.collect::<Vec<_>>();
diff --git a/datafusion/core/tests/datasource/object_store_access.rs b/datafusion/core/tests/datasource/object_store_access.rs
index c494f0ee8e..215725cf04 100644
--- a/datafusion/core/tests/datasource/object_store_access.rs
+++ b/datafusion/core/tests/datasource/object_store_access.rs
@@ -1395,7 +1395,6 @@ impl Display for RequestDetails {
if get_options.head {
write!(f, " head=true")?;
}
- Ok(())
}
RequestDetails::GetRanges { path, ranges } => {
write!(f, "GET (ranges) path={path}")?;
@@ -1408,30 +1407,27 @@ impl Display for RequestDetails {
write!(f, "{}", display_range(range))?;
}
}
- Ok(())
}
RequestDetails::List { prefix } => {
write!(f, "LIST")?;
if let Some(prefix) = prefix {
write!(f, " prefix={prefix}")?;
}
- Ok(())
}
RequestDetails::ListWithDelimiter { prefix } => {
write!(f, "LIST (with delimiter)")?;
if let Some(prefix) = prefix {
write!(f, " prefix={prefix}")?;
}
- Ok(())
}
RequestDetails::ListWithOffset { prefix, offset } => {
write!(f, "LIST (with offset) offset={offset}")?;
if let Some(prefix) = prefix {
write!(f, " prefix={prefix}")?;
}
- Ok(())
}
}
+ Ok(())
}
}
diff --git a/datafusion/core/tests/memory_limit/memory_limit_validation/utils.rs b/datafusion/core/tests/memory_limit/memory_limit_validation/utils.rs
index 788b8f4942..aae30418b2 100644
--- a/datafusion/core/tests/memory_limit/memory_limit_validation/utils.rs
+++ b/datafusion/core/tests/memory_limit/memory_limit_validation/utils.rs
@@ -70,15 +70,7 @@ where
);
if let Some(process) = sys.process(pid) {
let rss_bytes = process.memory();
- max_rss_clone
- .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |current| {
- if rss_bytes as usize > current {
- Some(rss_bytes as usize)
- } else {
- None
- }
- })
- .ok();
+ max_rss_clone.fetch_max(rss_bytes as usize, Ordering::Relaxed);
} else {
// Process no longer exists
break;
diff --git a/datafusion/datasource-parquet/src/source.rs b/datafusion/datasource-parquet/src/source.rs
index a5c165abb1..4959a56ce6 100644
--- a/datafusion/datasource-parquet/src/source.rs
+++ b/datafusion/datasource-parquet/src/source.rs
@@ -844,15 +844,14 @@ impl FileSource for ParquetSource {
)?;
}
}
- Ok(())
}
DisplayFormatType::TreeRender => {
if let Some(predicate) = self.filter() {
writeln!(f, "predicate={}", fmt_sql(predicate.as_ref()))?;
}
- Ok(())
}
}
+ Ok(())
}
fn try_pushdown_filters(
diff --git a/datafusion/datasource/src/mod.rs b/datafusion/datasource/src/mod.rs
index 6135835616..86549a96b3 100644
--- a/datafusion/datasource/src/mod.rs
+++ b/datafusion/datasource/src/mod.rs
@@ -42,7 +42,7 @@ pub mod memory;
pub mod morsel;
pub mod projection;
/// Protobuf conversions for [`FileRange`], [`PartitionedFile`] and
-/// [`FileGroup`](crate::file_groups::FileGroup), gated on the `proto` feature.
+/// [`FileGroup`], gated on the `proto` feature.
#[cfg(feature = "proto")]
mod proto;
pub mod schema_adapter;
diff --git a/datafusion/execution/src/memory_pool/mod.rs b/datafusion/execution/src/memory_pool/mod.rs
index 09cef6ddd4..2686f7ef38 100644
--- a/datafusion/execution/src/memory_pool/mod.rs
+++ b/datafusion/execution/src/memory_pool/mod.rs
@@ -412,7 +412,7 @@ impl MemoryReservation {
/// Panics if `capacity` exceeds [`Self::size`]
pub fn shrink(&self, capacity: usize) {
self.size
- .fetch_update(
+ .try_update(
atomic::Ordering::Relaxed,
atomic::Ordering::Relaxed,
|prev| prev.checked_sub(capacity),
@@ -430,7 +430,7 @@ impl MemoryReservation {
pub fn try_shrink(&self, capacity: usize) -> Result<usize> {
let prev = self
.size
- .fetch_update(
+ .try_update(
atomic::Ordering::Relaxed,
atomic::Ordering::Relaxed,
|prev| prev.checked_sub(capacity),
@@ -495,7 +495,7 @@ impl MemoryReservation {
/// Panics if `capacity` exceeds [`Self::size`]
pub fn split(&self, capacity: usize) -> MemoryReservation {
self.size
- .fetch_update(
+ .try_update(
atomic::Ordering::Relaxed,
atomic::Ordering::Relaxed,
|prev| prev.checked_sub(capacity),
diff --git a/datafusion/execution/src/memory_pool/pool.rs b/datafusion/execution/src/memory_pool/pool.rs
index f291d7052a..0d05efb8be 100644
--- a/datafusion/execution/src/memory_pool/pool.rs
+++ b/datafusion/execution/src/memory_pool/pool.rs
@@ -105,7 +105,7 @@ impl MemoryPool for GreedyMemoryPool {
fn try_grow(&self, reservation: &MemoryReservation, additional: usize) -> Result<()> {
self.used
- .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |used| {
+ .try_update(Ordering::Relaxed, Ordering::Relaxed, |used| {
let new_used = used + additional;
(new_used <= self.pool_size).then_some(new_used)
})
diff --git a/datafusion/expr/src/lib.rs b/datafusion/expr/src/lib.rs
index 48ed38e8f4..8a21dc6693 100644
--- a/datafusion/expr/src/lib.rs
+++ b/datafusion/expr/src/lib.rs
@@ -70,7 +70,7 @@ pub mod dml {
}
pub mod planner;
/// Protobuf conversions for [`WindowFrame`], [`WindowFrameBound`],
-/// [`WindowFrameUnits`], [`MergeIntoClauseKind`](dml::MergeIntoClauseKind) and
+/// [`WindowFrameUnits`], [`MergeIntoClauseKind`] and
/// [`NullTreatment`](expr::NullTreatment), gated on the `proto` feature.
#[cfg(feature = "proto")]
mod proto;
diff --git a/datafusion/expr/src/proto.rs b/datafusion/expr/src/proto.rs
index 00b3402108..8bced7106f 100644
--- a/datafusion/expr/src/proto.rs
+++ b/datafusion/expr/src/proto.rs
@@ -17,8 +17,7 @@
//! Protobuf conversions for the expression types owned by this crate:
//! [`WindowFrame`], [`WindowFrameBound`], [`WindowFrameUnits`],
-//! [`MergeIntoClauseKind`](crate::dml::MergeIntoClauseKind) and
-//! [`NullTreatment`](crate::expr::NullTreatment).
+//! [`MergeIntoClauseKind`] and [`NullTreatment`](crate::expr::NullTreatment).
//!
//! These are plain [`From`] / [`TryFrom`] impls rather than something taking a
//! codec: every field is either an enum tag or a [`ScalarValue`], so the
diff --git a/datafusion/functions-aggregate/src/first_last.rs b/datafusion/functions-aggregate/src/first_last.rs
index d9254c0d2a..17be6359cf 100644
--- a/datafusion/functions-aggregate/src/first_last.rs
+++ b/datafusion/functions-aggregate/src/first_last.rs
@@ -900,17 +900,12 @@ impl<S: ValueState + 'static> GroupsAccumulator for FirstLastGroupsAccumulator<S
values: &[ArrayRef],
opt_filter: Option<&BooleanArray>,
) -> Result<Vec<ArrayRef>> {
+ let filter = opt_filter
+ .cloned()
+ .unwrap_or_else(|| BooleanArray::from(vec![true; values[0].len()]));
let mut result = values.to_vec();
- match opt_filter {
- Some(f) => {
- result.push(Arc::new(f.clone()));
- Ok(result)
- }
- None => {
- result.push(Arc::new(BooleanArray::from(vec![true; values[0].len()])));
- Ok(result)
- }
- }
+ result.push(Arc::new(filter));
+ Ok(result)
}
}
diff --git a/datafusion/functions/src/core/getfield.rs b/datafusion/functions/src/core/getfield.rs
index 2b75623daa..07ae4b1f2e 100644
--- a/datafusion/functions/src/core/getfield.rs
+++ b/datafusion/functions/src/core/getfield.rs
@@ -327,15 +327,13 @@ impl ScalarUDFImpl for GetFieldFunc {
match current_field.data_type() {
DataType::Map(map_field, _) => {
match map_field.data_type() {
- DataType::Struct(fields) if fields.len() == 2 => {
+ DataType::Struct(fields)
+ if let [_, value_field] = &fields[..] =>
+ {
// Arrow's MapArray is essentially a ListArray of structs with two columns. They are
// often named "key", and "value", but we don't require any specific naming here;
// instead, we assume that the second column is the "value" column both here and in
// execution.
- let value_field = fields
- .get(1)
- .expect("fields should have exactly two members");
-
current_field = Arc::new(
value_field.as_ref().clone().with_nullable(true),
);
@@ -351,11 +349,8 @@ impl ScalarUDFImpl for GetFieldFunc {
// the underlying struct, then wrap the result back in the
// same Dictionary type so the promised type matches execution.
DataType::Dictionary(key_type, value_type)
- if matches!(value_type.as_ref(), DataType::Struct(_)) =>
+ if let DataType::Struct(fields) = value_type.as_ref() =>
{
- let DataType::Struct(fields) = value_type.as_ref() else {
- unreachable!()
- };
let field_name = sv
.as_ref()
.and_then(|sv| {
diff --git a/datafusion/physical-plan/src/coalesce_batches.rs b/datafusion/physical-plan/src/coalesce_batches.rs
index 9da7df822f..7068dc28b2 100644
--- a/datafusion/physical-plan/src/coalesce_batches.rs
+++ b/datafusion/physical-plan/src/coalesce_batches.rs
@@ -137,17 +137,15 @@ impl DisplayAs for CoalesceBatchesExec {
if let Some(fetch) = self.fetch {
write!(f, ", fetch={fetch}")?;
}
-
- Ok(())
}
DisplayFormatType::TreeRender => {
writeln!(f, "target_batch_size={}", self.target_batch_size)?;
if let Some(fetch) = self.fetch {
write!(f, "limit={fetch}")?;
}
- Ok(())
}
}
+ Ok(())
}
}
diff --git a/datafusion/physical-plan/src/repartition/mod.rs b/datafusion/physical-plan/src/repartition/mod.rs
index d2d8ec38da..3df29b577c 100644
--- a/datafusion/physical-plan/src/repartition/mod.rs
+++ b/datafusion/physical-plan/src/repartition/mod.rs
@@ -1628,7 +1628,6 @@ impl DisplayAs for RepartitionExec {
if let Some(sort_exprs) = self.sort_exprs() {
write!(f, ", sort_exprs={}", sort_exprs.clone())?;
}
- Ok(())
}
DisplayFormatType::TreeRender => {
writeln!(f, "partitioning_scheme={}", self.partitioning())?;
@@ -1643,9 +1642,9 @@ impl DisplayAs for RepartitionExec {
if self.preserve_order {
writeln!(f, "preserve_order={}", self.preserve_order)?;
}
- Ok(())
}
}
+ Ok(())
}
}
diff --git a/datafusion/physical-plan/src/sorts/sort_preserving_merge.rs b/datafusion/physical-plan/src/sorts/sort_preserving_merge.rs
index 3551631b41..7c924ff32b 100644
--- a/datafusion/physical-plan/src/sorts/sort_preserving_merge.rs
+++ b/datafusion/physical-plan/src/sorts/sort_preserving_merge.rs
@@ -199,8 +199,6 @@ impl DisplayAs for SortPreservingMergeExec {
if let Some(fetch) = self.fetch {
write!(f, ", fetch={fetch}")?;
}
-
- Ok(())
}
DisplayFormatType::TreeRender => {
if let Some(fetch) = self.fetch {
@@ -213,10 +211,9 @@ impl DisplayAs for SortPreservingMergeExec {
write!(f, ", ")?;
}
}
-
- Ok(())
}
}
+ Ok(())
}
}
diff --git a/datafusion/physical-plan/src/streaming.rs b/datafusion/physical-plan/src/streaming.rs
index dd57f958e8..e58de52ae9 100644
--- a/datafusion/physical-plan/src/streaming.rs
+++ b/datafusion/physical-plan/src/streaming.rs
@@ -239,8 +239,6 @@ impl DisplayAs for StreamingTableExec {
}
display_orderings(f, &self.projected_output_ordering)?;
-
- Ok(())
}
DisplayFormatType::TreeRender => {
if self.infinite {
@@ -251,10 +249,9 @@ impl DisplayAs for StreamingTableExec {
} else {
write!(f, "limit=None")?;
}
-
- Ok(())
}
}
+ Ok(())
}
}
diff --git a/datafusion/physical-plan/src/topk/mod.rs b/datafusion/physical-plan/src/topk/mod.rs
index d4405c1f12..05743472f9 100644
--- a/datafusion/physical-plan/src/topk/mod.rs
+++ b/datafusion/physical-plan/src/topk/mod.rs
@@ -287,7 +287,7 @@ impl TopKDynamicFilters {
fn mark_topk_emitted(&self) {
let previous = self
.remaining_topk_emitters
- .fetch_update(
+ .try_update(
AtomicOrdering::AcqRel,
AtomicOrdering::Acquire,
|remaining| remaining.checked_sub(1),
diff --git a/datafusion/substrait/src/logical_plan/consumer/rel/fetch_rel.rs b/datafusion/substrait/src/logical_plan/consumer/rel/fetch_rel.rs
index 12a8a77199..ebc73a3ee3 100644
--- a/datafusion/substrait/src/logical_plan/consumer/rel/fetch_rel.rs
+++ b/datafusion/substrait/src/logical_plan/consumer/rel/fetch_rel.rs
@@ -22,6 +22,10 @@ use datafusion::logical_expr::{LogicalPlan, LogicalPlanBuilder, lit};
use substrait::proto::{FetchRel, fetch_rel};
#[async_recursion]
+#[expect(
+ clippy::double_must_use,
+ reason = "`async_recursion` adds `#[must_use]` to the boxed future it returns"
+)]
pub async fn from_fetch_rel(
consumer: &impl SubstraitConsumer,
fetch: &FetchRel,
diff --git a/datafusion/substrait/src/logical_plan/consumer/rel/filter_rel.rs b/datafusion/substrait/src/logical_plan/consumer/rel/filter_rel.rs
index 645b982782..ac527d95c9 100644
--- a/datafusion/substrait/src/logical_plan/consumer/rel/filter_rel.rs
+++ b/datafusion/substrait/src/logical_plan/consumer/rel/filter_rel.rs
@@ -22,6 +22,10 @@ use datafusion::logical_expr::{LogicalPlan, LogicalPlanBuilder};
use substrait::proto::FilterRel;
#[async_recursion]
+#[expect(
+ clippy::double_must_use,
+ reason = "`async_recursion` adds `#[must_use]` to the boxed future it returns"
+)]
pub async fn from_filter_rel(
consumer: &impl SubstraitConsumer,
filter: &FilterRel,
diff --git a/datafusion/substrait/src/logical_plan/consumer/rel/mod.rs b/datafusion/substrait/src/logical_plan/consumer/rel/mod.rs
index 038ada115b..f95c2e7dd2 100644
--- a/datafusion/substrait/src/logical_plan/consumer/rel/mod.rs
+++ b/datafusion/substrait/src/logical_plan/consumer/rel/mod.rs
@@ -50,6 +50,10 @@ use substrait::proto::{Rel, RelCommon, rel_common};
/// Convert Substrait Rel to DataFusion DataFrame
#[async_recursion]
+#[expect(
+ clippy::double_must_use,
+ reason = "`async_recursion` adds `#[must_use]` to the boxed future it returns"
+)]
pub async fn from_substrait_rel(
consumer: &impl SubstraitConsumer,
relation: &Rel,
diff --git a/datafusion/substrait/src/logical_plan/consumer/rel/project_rel.rs b/datafusion/substrait/src/logical_plan/consumer/rel/project_rel.rs
index fa93add0ff..211ccdd848 100644
--- a/datafusion/substrait/src/logical_plan/consumer/rel/project_rel.rs
+++ b/datafusion/substrait/src/logical_plan/consumer/rel/project_rel.rs
@@ -29,6 +29,10 @@ use std::sync::Arc;
use substrait::proto::ProjectRel;
#[async_recursion]
+#[expect(
+ clippy::double_must_use,
+ reason = "`async_recursion` adds `#[must_use]` to the boxed future it returns"
+)]
pub async fn from_project_rel(
consumer: &impl SubstraitConsumer,
p: &ProjectRel,
diff --git a/datafusion/substrait/src/physical_plan/consumer.rs b/datafusion/substrait/src/physical_plan/consumer.rs
index 3c0df01b4a..eb971e0a3c 100644
--- a/datafusion/substrait/src/physical_plan/consumer.rs
+++ b/datafusion/substrait/src/physical_plan/consumer.rs
@@ -46,6 +46,10 @@ use substrait::proto::{
/// Convert Substrait Rel to DataFusion ExecutionPlan
#[async_recursion]
+#[expect(
+ clippy::double_must_use,
+ reason = "`async_recursion` adds `#[must_use]` to the boxed future it returns"
+)]
pub async fn from_substrait_rel(
_ctx: &SessionContext,
rel: &Rel,
diff --git a/dev/depcheck/rust-toolchain.toml b/dev/depcheck/rust-toolchain.toml
index 8a06035a6a..d3483e9f75 100644
--- a/dev/depcheck/rust-toolchain.toml
+++ b/dev/depcheck/rust-toolchain.toml
@@ -19,5 +19,5 @@
# to compile this workspace and run CI jobs.
[toolchain]
-channel = "1.98.1"
+channel = "1.99.0"
components = ["rustfmt", "clippy"]
diff --git a/docs/source/contributor-guide/development_environment.md b/docs/source/contributor-guide/development_environment.md
index 20cfd6edd0..f54ac75d89 100644
--- a/docs/source/contributor-guide/development_environment.md
+++ b/docs/source/contributor-guide/development_environment.md
@@ -108,7 +108,7 @@ DataFusion is written in Rust and it uses a standard rust toolkit:
- `rustup update stable` DataFusion generally uses the latest stable release of Rust, though it may lag when new Rust toolchains release
- See which toolchain is currently pinned in the [`rust-toolchain.toml`](https://github.com/apache/datafusion/blob/main/rust-toolchain.toml) file
- - This can cause issues such as not having the rust-analyzer component installed for the specified toolchain, in which case just install it manually, e.g. `rustup component add --toolchain 1.98.1 rust-analyzer`
+ - This can cause issues such as not having the rust-analyzer component installed for the specified toolchain, in which case just install it manually, e.g. `rustup component add --toolchain 1.99.0 rust-analyzer`
- `cargo build`
- `cargo fmt` to format the code
- etc.
diff --git a/docs/source/library-user-guide/upgrading/56.0.0.md b/docs/source/library-user-guide/upgrading/56.0.0.md
index 1f1855f76f..6c251c5cfb 100644
--- a/docs/source/library-user-guide/upgrading/56.0.0.md
+++ b/docs/source/library-user-guide/upgrading/56.0.0.md
@@ -25,6 +25,12 @@
in this section pertains to features and changes that have already been merged
to the main branch and are awaiting release in this version.
+### `MSRV` updated to 1.95.0
+
+The Minimum Supported Rust Version (MSRV) has been updated to [`1.95.0`].
+
+[`1.95.0`]: https://releases.rs/docs/1.95.0/
+
### Upgrade arrow/parquet to 60.0.0 and object_store to 0.14.2
DataFusion 56.0.0 uses `arrow` and `parquet` 60.0.0, and `object_store` 0.14.2.
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
index 8a06035a6a..d3483e9f75 100644
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -19,5 +19,5 @@
# to compile this workspace and run CI jobs.
[toolchain]
-channel = "1.98.1"
+channel = "1.99.0"
components = ["rustfmt", "clippy"]
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org