From 1eb9b134f52ef9a3ffa28075bc1a1515bcfbaa8c Mon Sep 17 00:00:00 2001 From: Christopher Hotchkiss Date: Sat, 2 Aug 2025 10:46:29 -0700 Subject: [PATCH 1/5] Change visibility of Args new function Currently the Args new function is scope constrained to pub(super) but this stops me from being able to construct Args structs in unit tests. --- library/std/src/sys/args/common.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/args/common.rs b/library/std/src/sys/args/common.rs index e787105a05a73..33f3794ee6339 100644 --- a/library/std/src/sys/args/common.rs +++ b/library/std/src/sys/args/common.rs @@ -12,7 +12,7 @@ impl !Sync for Args {} impl Args { #[inline] - pub(super) fn new(args: Vec) -> Self { + pub fn new(args: Vec) -> Self { Args { iter: args.into_iter() } } } From 904e2af3a97e81637b9816d71411d52e26bd1550 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Fri, 1 Aug 2025 18:25:57 +0200 Subject: [PATCH 2/5] Port `#[coroutine]` to the new attribute system Related to https://github.com/rust-lang/rust/issues/131229#issue-2565886367. --- compiler/rustc_ast_lowering/src/expr.rs | 18 ++++++------------ .../rustc_attr_parsing/src/attributes/body.rs | 15 +++++++++++++++ .../rustc_attr_parsing/src/attributes/mod.rs | 1 + compiler/rustc_attr_parsing/src/context.rs | 2 ++ .../rustc_hir/src/attrs/data_structures.rs | 3 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 10 +++++----- tests/ui/attributes/malformed-attrs.stderr | 15 +++++++++------ 8 files changed, 42 insertions(+), 23 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/body.rs diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 1245d48975470..fb42cfea30b41 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -98,7 +98,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let expr_hir_id = self.lower_node_id(e.id); - self.lower_attrs(expr_hir_id, &e.attrs, e.span); + let attrs = self.lower_attrs(expr_hir_id, &e.attrs, e.span); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -232,10 +232,10 @@ impl<'hir> LoweringContext<'_, 'hir> { *fn_arg_span, ), None => self.lower_expr_closure( + attrs, binder, *capture_clause, e.id, - expr_hir_id, *constness, *movability, fn_decl, @@ -1052,10 +1052,10 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_closure( &mut self, + attrs: &[rustc_hir::Attribute], binder: &ClosureBinder, capture_clause: CaptureBy, closure_id: NodeId, - closure_hir_id: hir::HirId, constness: Const, movability: Movability, decl: &FnDecl, @@ -1067,15 +1067,9 @@ impl<'hir> LoweringContext<'_, 'hir> { let (binder_clause, generic_params) = self.lower_closure_binder(binder); let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| { - let mut coroutine_kind = if this - .attrs - .get(&closure_hir_id.local_id) - .is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine))) - { - Some(hir::CoroutineKind::Coroutine(Movability::Movable)) - } else { - None - }; + + let mut coroutine_kind = find_attr!(attrs, AttributeKind::Coroutine(_) => hir::CoroutineKind::Coroutine(Movability::Movable)); + // FIXME(contracts): Support contracts on closures? let body_id = this.lower_fn_body(decl, None, |this| { this.coroutine_kind = coroutine_kind; diff --git a/compiler/rustc_attr_parsing/src/attributes/body.rs b/compiler/rustc_attr_parsing/src/attributes/body.rs new file mode 100644 index 0000000000000..ab9330216f6c6 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/body.rs @@ -0,0 +1,15 @@ +//! Attributes that can be found in function body. + +use rustc_hir::attrs::AttributeKind; +use rustc_span::{Symbol, sym}; + +use super::{NoArgsAttributeParser, OnDuplicate}; +use crate::context::Stage; + +pub(crate) struct CoroutineParser; + +impl NoArgsAttributeParser for CoroutineParser { + const PATH: &[Symbol] = &[sym::coroutine]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const CREATE: fn(rustc_span::Span) -> AttributeKind = |span| AttributeKind::Coroutine(span); +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index c574ef78bdf79..f7946ade6d2b2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -26,6 +26,7 @@ use crate::parser::ArgParser; use crate::session_diagnostics::UnusedMultiple; pub(crate) mod allow_unstable; +pub(crate) mod body; pub(crate) mod cfg; pub(crate) mod cfg_old; pub(crate) mod codegen_attrs; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index b51db9b4b9e38..ec74f6fd1c6f4 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -16,6 +16,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{ AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser, }; +use crate::attributes::body::CoroutineParser; use crate::attributes::codegen_attrs::{ ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser, @@ -184,6 +185,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 80618422b56d6..d9d2ec48948e7 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -297,6 +297,9 @@ pub enum AttributeKind { /// Represents `#[const_trait]`. ConstTrait(Span), + /// Represents `#[coroutine]`. + Coroutine(Span), + /// Represents `#[coverage(..)]`. Coverage(Span, CoverageAttrKind), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 9644a597a3117..b66e5bbeabe73 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -28,6 +28,7 @@ impl AttributeKind { ConstStability { .. } => Yes, ConstStabilityIndirect => No, ConstTrait(..) => No, + Coroutine(..) => No, Coverage(..) => No, DenyExplicitImpl(..) => No, Deprecation { .. } => Yes, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2663d5fe99c7a..890028d977d30 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -324,6 +324,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &Attribute::Parsed(AttributeKind::Coverage(attr_span, _)) => { self.check_coverage(attr_span, span, target) } + &Attribute::Parsed(AttributeKind::Coroutine(attr_span)) => { + self.check_coroutine(attr_span, target) + } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); match attr.path().as_slice() { @@ -390,9 +393,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => { self.check_autodiff(hir_id, attr, span, target) } - [sym::coroutine, ..] => { - self.check_coroutine(attr, target); - } [sym::linkage, ..] => self.check_linkage(attr, span, target), [ // ok @@ -2651,11 +2651,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_coroutine(&self, attr: &Attribute, target: Target) { + fn check_coroutine(&self, attr_span: Span, target: Target) { match target { Target::Closure => return, _ => { - self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr.span() }); + self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr_span }); } } } diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 1b51075b4e888..e8ae4715398f4 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -55,12 +55,6 @@ error: malformed `patchable_function_entry` attribute input LL | #[patchable_function_entry] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` -error: malformed `coroutine` attribute input - --> $DIR/malformed-attrs.rs:108:5 - | -LL | #[coroutine = 63] || {} - | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[coroutine]` - error: malformed `must_not_suspend` attribute input --> $DIR/malformed-attrs.rs:129:1 | @@ -436,6 +430,15 @@ LL | #[proc_macro = 18] | | didn't expect any arguments here | help: must be of the form: `#[proc_macro]` +error[E0565]: malformed `coroutine` attribute input + --> $DIR/malformed-attrs.rs:108:5 + | +LL | #[coroutine = 63] || {} + | ^^^^^^^^^^^^----^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#[coroutine]` + error[E0565]: malformed `proc_macro_attribute` attribute input --> $DIR/malformed-attrs.rs:113:1 | From b3317dd0550a7e04997eacea353d936306e5eac0 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 4 Aug 2025 22:20:30 +0200 Subject: [PATCH 3/5] Correct the use of `must_use` on btree::IterMut Signed-off-by: Jonathan Brouwer --- library/alloc/src/collections/btree/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 17c16e4aafff7..acbbb6df9a5a5 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -382,6 +382,7 @@ impl<'a, K: 'a, V: 'a> Default for Iter<'a, K, V> { /// documentation for more. /// /// [`iter_mut`]: BTreeMap::iter_mut +#[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, K: 'a, V: 'a> { range: LazyLeafRange, K, V>, @@ -391,7 +392,6 @@ pub struct IterMut<'a, K: 'a, V: 'a> { _marker: PhantomData<&'a mut (K, V)>, } -#[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "collection_debug", since = "1.17.0")] impl fmt::Debug for IterMut<'_, K, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { From 6cdf74786f141aea4d8acb8aa64ae1f0ba3aa2de Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Tue, 5 Aug 2025 00:29:13 +0900 Subject: [PATCH 4/5] Add regression tests for seemingly fixed issues --- .../const-closure-issue-125866-error.rs | 24 ++++++++++++++++++ .../const-closure-issue-125866-error.stderr | 11 ++++++++ .../const-closure-issue-125866-pass.rs | 25 +++++++++++++++++++ .../const-fn-trait-bound-issue-104314.rs | 13 ++++++++++ 4 files changed, 73 insertions(+) create mode 100644 tests/ui/traits/const-traits/const-closure-issue-125866-error.rs create mode 100644 tests/ui/traits/const-traits/const-closure-issue-125866-error.stderr create mode 100644 tests/ui/traits/const-traits/const-closure-issue-125866-pass.rs create mode 100644 tests/ui/traits/const-traits/const-fn-trait-bound-issue-104314.rs diff --git a/tests/ui/traits/const-traits/const-closure-issue-125866-error.rs b/tests/ui/traits/const-traits/const-closure-issue-125866-error.rs new file mode 100644 index 0000000000000..7a44920bb729d --- /dev/null +++ b/tests/ui/traits/const-traits/const-closure-issue-125866-error.rs @@ -0,0 +1,24 @@ +#![allow(incomplete_features)] +#![feature(const_closures, const_trait_impl)] + +const fn create_array(mut f: impl FnMut(usize) -> u32 + Copy) -> [u32; N] { + let mut array = [0; N]; + let mut i = 0; + loop { + array[i] = f(i); + //~^ ERROR the trait bound `impl FnMut(usize) -> u32 + Copy: [const] FnMut(usize)` is not satisfied [E0277] + i += 1; + if i == N { + break; + } + } + array +} + +fn main() { + let x = create_array(const |i| 2 * i as u32); + assert_eq!(x, [0, 2, 4, 6, 8]); + + let y = create_array(const |i| 2 * i as u32 + 1); + assert_eq!(y, [1, 3, 5, 7, 9]); +} diff --git a/tests/ui/traits/const-traits/const-closure-issue-125866-error.stderr b/tests/ui/traits/const-traits/const-closure-issue-125866-error.stderr new file mode 100644 index 0000000000000..1eadd1d842691 --- /dev/null +++ b/tests/ui/traits/const-traits/const-closure-issue-125866-error.stderr @@ -0,0 +1,11 @@ +error[E0277]: the trait bound `impl FnMut(usize) -> u32 + Copy: [const] FnMut(usize)` is not satisfied + --> $DIR/const-closure-issue-125866-error.rs:8:22 + | +LL | array[i] = f(i); + | - ^ + | | + | required by a bound introduced by this call + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const-closure-issue-125866-pass.rs b/tests/ui/traits/const-traits/const-closure-issue-125866-pass.rs new file mode 100644 index 0000000000000..da8014c38de3e --- /dev/null +++ b/tests/ui/traits/const-traits/const-closure-issue-125866-pass.rs @@ -0,0 +1,25 @@ +//@ run-pass + +#![allow(incomplete_features)] +#![feature(const_closures, const_trait_impl)] + +const fn create_array(mut f: impl [const] FnMut(usize) -> u32 + Copy) -> [u32; N] { + let mut array = [0; N]; + let mut i = 0; + loop { + array[i] = f(i); + i += 1; + if i == N { + break; + } + } + array +} + +fn main() { + let x = create_array(const |i| 2 * i as u32); + assert_eq!(x, [0, 2, 4, 6, 8]); + + let y = create_array(const |i| 2 * i as u32 + 1); + assert_eq!(y, [1, 3, 5, 7, 9]); +} diff --git a/tests/ui/traits/const-traits/const-fn-trait-bound-issue-104314.rs b/tests/ui/traits/const-traits/const-fn-trait-bound-issue-104314.rs new file mode 100644 index 0000000000000..09c89c9cecde7 --- /dev/null +++ b/tests/ui/traits/const-traits/const-fn-trait-bound-issue-104314.rs @@ -0,0 +1,13 @@ +//@ check-pass + +#![feature(const_trait_impl, const_destruct, const_clone)] + +use std::marker::Destruct; + +const fn f T + [const] Destruct>(_: F) {} + +const fn g() { + f(::clone); +} + +fn main() {} From df61951a19927e10037d13f502b844102026a9d9 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Tue, 5 Aug 2025 10:42:03 +0200 Subject: [PATCH 5/5] autolabel PRs that change etc tests as `F-explicit_tail_calls` --- triagebot.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index fefff78d64eef..e8c15bb9bfdbe 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -287,6 +287,11 @@ trigger_files = [ "compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs", ] +[autolabel."F-explicit_tail_calls"] +trigger_files = [ + "tests/ui/explicit-tail-calls", +] + [autolabel."T-rustdoc-frontend"] trigger_labels = [ "A-rustdoc-search",