From c58c06a6f51f2de7a869e278d08438c34a6ea86f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 11 Mar 2025 15:33:37 +0100 Subject: [PATCH 01/24] Return blocks from DropTree::build_mir Rather than requiring the user to pass in a correctly sized blocks map. --- compiler/rustc_mir_build/src/builder/scope.rs | 37 +++++++++---------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 27ff01b48034b..e56c0ae92cac6 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -305,27 +305,25 @@ impl DropTree { } /// Builds the MIR for a given drop tree. - /// - /// `blocks` should have the same length as `self.drops`, and may have its - /// first value set to some already existing block. fn build_mir<'tcx, T: DropTreeBuilder<'tcx>>( &mut self, cfg: &mut CFG<'tcx>, - blocks: &mut IndexVec>, - ) { + root_node: Option, + ) -> IndexVec> { debug!("DropTree::build_mir(drops = {:#?})", self); - assert_eq!(blocks.len(), self.drops.len()); - self.assign_blocks::(cfg, blocks); - self.link_blocks(cfg, blocks) + let mut blocks = self.assign_blocks::(cfg, root_node); + self.link_blocks(cfg, &mut blocks); + + blocks } /// Assign blocks for all of the drops in the drop tree that need them. fn assign_blocks<'tcx, T: DropTreeBuilder<'tcx>>( &mut self, cfg: &mut CFG<'tcx>, - blocks: &mut IndexVec>, - ) { + root_node: Option, + ) -> IndexVec> { // StorageDead statements can share blocks with each other and also with // a Drop terminator. We iterate through the drops to find which drops // need their own block. @@ -342,8 +340,11 @@ impl DropTree { Own, } + let mut blocks = IndexVec::from_elem(None, &self.drops); + blocks[ROOT_NODE] = root_node; + let mut needs_block = IndexVec::from_elem(Block::None, &self.drops); - if blocks[ROOT_NODE].is_some() { + if root_node.is_some() { // In some cases (such as drops for `continue`) the root node // already has a block. In this case, make sure that we don't // override it. @@ -385,6 +386,8 @@ impl DropTree { debug!("assign_blocks: blocks = {:#?}", blocks); assert!(entry_points.is_empty()); + + blocks } fn link_blocks<'tcx>( @@ -1574,10 +1577,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { span: Span, continue_block: Option, ) -> Option> { - let mut blocks = IndexVec::from_elem(None, &drops.drops); - blocks[ROOT_NODE] = continue_block; - - drops.build_mir::(&mut self.cfg, &mut blocks); + let blocks = drops.build_mir::(&mut self.cfg, continue_block); let is_coroutine = self.coroutine.is_some(); // Link the exit drop tree to unwind drop tree. @@ -1633,8 +1633,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { let drops = &mut self.scopes.coroutine_drops; let cfg = &mut self.cfg; let fn_span = self.fn_span; - let mut blocks = IndexVec::from_elem(None, &drops.drops); - drops.build_mir::(cfg, &mut blocks); + let blocks = drops.build_mir::(cfg, None); if let Some(root_block) = blocks[ROOT_NODE] { cfg.terminate( root_block, @@ -1670,9 +1669,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { fn_span: Span, resume_block: &mut Option, ) { - let mut blocks = IndexVec::from_elem(None, &drops.drops); - blocks[ROOT_NODE] = *resume_block; - drops.build_mir::(cfg, &mut blocks); + let blocks = drops.build_mir::(cfg, *resume_block); if let (None, Some(resume)) = (*resume_block, blocks[ROOT_NODE]) { cfg.terminate(resume, SourceInfo::outermost(fn_span), TerminatorKind::UnwindResume); From 8dc0c0ece93164da4d10a020a79201c95341bc9f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 12 Mar 2025 13:39:26 +0100 Subject: [PATCH 02/24] Simplify lit_to_mir_constant a bit --- .../src/builder/expr/as_constant.rs | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index f743ea60a456c..64d092e035451 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -105,23 +105,19 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx> return Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar)); } - let trunc = |n, width: ty::UintTy| { - let width = width - .normalize(tcx.data_layout.pointer_size.bits().try_into().unwrap()) - .bit_width() - .unwrap(); - let width = Size::from_bits(width); + let lit_ty = match *ty.kind() { + ty::Pat(base, _) => base, + _ => ty, + }; + + let trunc = |n| { + let width = lit_ty.primitive_size(tcx); trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); let result = width.truncate(n); trace!("trunc result: {}", result); ConstValue::Scalar(Scalar::from_uint(result, width)) }; - let lit_ty = match *ty.kind() { - ty::Pat(base, _) => base, - _ => ty, - }; - let value = match (lit, lit_ty.kind()) { (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => { let s = s.as_str(); @@ -149,11 +145,10 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx> (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => { ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1))) } - (ast::LitKind::Int(n, _), ty::Uint(ui)) if !neg => trunc(n.get(), *ui), - (ast::LitKind::Int(n, _), ty::Int(i)) => trunc( - if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() }, - i.to_unsigned(), - ), + (ast::LitKind::Int(n, _), ty::Uint(_)) if !neg => trunc(n.get()), + (ast::LitKind::Int(n, _), ty::Int(_)) => { + trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() }) + } (ast::LitKind::Float(n, _), ty::Float(fty)) => { parse_float_into_constval(*n, *fty, neg).unwrap() } From edf65e735cd871d01149131f5d050293a9f1037c Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 12 Mar 2025 15:59:28 -0700 Subject: [PATCH 03/24] Add support for postfix yield expressions We had a discussion[1] today about whether postfix yield would make sense. It's easy enough to support both in the parser, so we might as well have both and see how people use it while the feature is experimental. [1]: https://rust-lang.zulipchat.com/#narrow/channel/481571-t-lang.2Fgen/topic/postfix-yield/with/505231568 --- compiler/rustc_parse/src/parser/expr.rs | 7 +++++ tests/ui/coroutine/postfix-yield.rs | 34 +++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 tests/ui/coroutine/postfix-yield.rs diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 9b2d562a69ecd..1df6283af2647 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1310,6 +1310,13 @@ impl<'a> Parser<'a> { return self.parse_match_block(lo, match_span, self_arg, MatchKind::Postfix); } + // Post-fix yield + if self.eat_keyword(exp!(Yield)) { + let yield_span = self.prev_token.span; + self.psess.gated_spans.gate(sym::yield_expr, yield_span); + return Ok(self.mk_expr(yield_span, ExprKind::Yield(Some(self_arg)))); + } + let fn_span_lo = self.token.span; let mut seg = self.parse_path_segment(PathStyle::Expr, None)?; self.check_trailing_angle_brackets(&seg, &[exp!(OpenParen)]); diff --git a/tests/ui/coroutine/postfix-yield.rs b/tests/ui/coroutine/postfix-yield.rs new file mode 100644 index 0000000000000..77b1c2a19d0a4 --- /dev/null +++ b/tests/ui/coroutine/postfix-yield.rs @@ -0,0 +1,34 @@ +// This demonstrates a proposed alternate or additional option of having yield in postfix position. + +//@ run-pass +//@ edition: 2024 + +#![feature(gen_blocks, coroutines, coroutine_trait, yield_expr)] + +use std::ops::{Coroutine, CoroutineState}; +use std::pin::pin; + +fn main() { + // generators (i.e. yield doesn't return anything useful) + let mut gn = gen { + yield 1; + 2.yield; + }; + + assert_eq!(gn.next(), Some(1)); + assert_eq!(gn.next(), Some(2)); + assert_eq!(gn.next(), None); + + //coroutines (i.e. yield returns something useful) + let mut coro = pin!( + #[coroutine] + |_: i32| { + let x = yield 1; + yield x + 2; + } + ); + + assert_eq!(coro.as_mut().resume(0), CoroutineState::Yielded(1)); + assert_eq!(coro.as_mut().resume(2), CoroutineState::Yielded(4)); + assert_eq!(coro.as_mut().resume(3), CoroutineState::Complete(())); +} From 1c0916a2b3cd6c595e1c7b69a31d507f7619bb67 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 12 Mar 2025 16:27:52 -0700 Subject: [PATCH 04/24] Preserve yield position during pretty printing --- compiler/rustc_ast/src/ast.rs | 11 ++++++++++- compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_ast/src/util/classify.rs | 4 ++-- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 2 +- compiler/rustc_ast_lowering/src/format.rs | 2 +- .../rustc_ast_pretty/src/pprust/state/expr.rs | 14 ++++++++++++-- .../rustc_builtin_macros/src/assert/context.rs | 2 +- compiler/rustc_parse/src/parser/expr.rs | 9 ++++++--- src/tools/rustfmt/src/utils.rs | 4 ++-- tests/pretty/postfix-yield.rs | 15 +++++++++++++++ tests/ui/coroutine/postfix-yield.rs | 6 +++--- 12 files changed, 55 insertions(+), 18 deletions(-) create mode 100644 tests/pretty/postfix-yield.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 1b831c454e6d5..9dcdd86834372 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1657,7 +1657,7 @@ pub enum ExprKind { Try(P), /// A `yield`, with an optional value to be yielded. - Yield(Option>), + Yield(Option>, YieldKind), /// A `do yeet` (aka `throw`/`fail`/`bail`/`raise`/whatever), /// with an optional value to be returned. @@ -1903,6 +1903,15 @@ pub enum MatchKind { Postfix, } +/// The kind of yield expression +#[derive(Clone, Copy, Encodable, Decodable, Debug, PartialEq)] +pub enum YieldKind { + /// yield expr { ... } + Prefix, + /// expr.yield { ... } + Postfix, +} + /// A literal in a meta item. #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub struct MetaItemLit { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 4a1636e6aec0e..5a9df6ffadf03 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1813,7 +1813,7 @@ pub fn walk_expr(vis: &mut T, Expr { kind, id, span, attrs, token ExprKind::Paren(expr) => { vis.visit_expr(expr); } - ExprKind::Yield(expr) => { + ExprKind::Yield(expr, _) => { visit_opt(expr, |expr| vis.visit_expr(expr)); } ExprKind::Try(expr) => vis.visit_expr(expr), diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index e43d78f6e7217..116847af9f497 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -182,7 +182,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option> { | Range(_, Some(e), _) | Ret(Some(e)) | Unary(_, e) - | Yield(Some(e)) + | Yield(Some(e), _) | Yeet(Some(e)) | Become(e) => { expr = e; @@ -217,7 +217,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option> { Break(_, None) | Range(_, None, _) | Ret(None) - | Yield(None) + | Yield(None, _) | Array(_) | Call(_, _) | MethodCall(_) diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index cfcb0e23cb5e6..a72e834e17a2f 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1269,7 +1269,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V try_visit!(visitor.visit_ty(container)); walk_list!(visitor, visit_ident, fields.iter()); } - ExprKind::Yield(optional_expression) => { + ExprKind::Yield(optional_expression, _) => { visit_opt!(visitor, visit_expr, optional_expression); } ExprKind::Try(subexpression) => try_visit!(visitor.visit_expr(subexpression)), diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 5bb6704dde45a..19a08f92ce75c 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -351,7 +351,7 @@ impl<'hir> LoweringContext<'_, 'hir> { rest, ) } - ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()), + ExprKind::Yield(opt_expr, _) => self.lower_expr_yield(e.span, opt_expr.as_deref()), ExprKind::Err(guar) => hir::ExprKind::Err(*guar), ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast( diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index faa47274f96ce..2bbf957feebe8 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -642,7 +642,7 @@ fn may_contain_yield_point(e: &ast::Expr) -> bool { type Result = ControlFlow<()>; fn visit_expr(&mut self, e: &ast::Expr) -> ControlFlow<()> { - if let ast::ExprKind::Await(_, _) | ast::ExprKind::Yield(_) = e.kind { + if let ast::ExprKind::Await(_, _) | ast::ExprKind::Yield(_, _) = e.kind { ControlFlow::Break(()) } else { visit::walk_expr(self, e) diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index e3c41f117abb8..9e53ed41c46c4 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -8,7 +8,7 @@ use rustc_ast::util::literal::escape_byte_str_symbol; use rustc_ast::util::parser::{self, ExprPrecedence, Fixity}; use rustc_ast::{ self as ast, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount, - FormatDebugHex, FormatSign, FormatTrait, token, + FormatDebugHex, FormatSign, FormatTrait, YieldKind, token, }; use crate::pp::Breaks::Inconsistent; @@ -761,7 +761,7 @@ impl<'a> State<'a> { self.print_expr(e, FixupContext::default()); self.pclose(); } - ast::ExprKind::Yield(e) => { + ast::ExprKind::Yield(e, YieldKind::Prefix) => { self.word("yield"); if let Some(expr) = e { @@ -773,6 +773,16 @@ impl<'a> State<'a> { ); } } + ast::ExprKind::Yield(e, YieldKind::Postfix) => { + // it's not possible to have a postfix yield with no expression. + let e = e.as_ref().unwrap(); + self.print_expr_cond_paren( + e, + e.precedence() < ExprPrecedence::Unambiguous, + fixup.leftmost_subexpression_with_dot(), + ); + self.word(".yield"); + } ast::ExprKind::Try(e) => { self.print_expr_cond_paren( e, diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index a949ab94f3ad7..54c3cebedfc0e 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -323,7 +323,7 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::While(_, _, _) | ExprKind::Yeet(_) | ExprKind::Become(_) - | ExprKind::Yield(_) + | ExprKind::Yield(_, _) | ExprKind::UnsafeBinderCast(..) => {} } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 1df6283af2647..cb04bbc240e49 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -17,6 +17,7 @@ use rustc_ast::{ self as ast, AnonConst, Arm, AttrStyle, AttrVec, BinOp, BinOpKind, BlockCheckMode, CaptureBy, ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl, FnRetTy, Label, MacCall, MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, + YieldKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -1314,7 +1315,9 @@ impl<'a> Parser<'a> { if self.eat_keyword(exp!(Yield)) { let yield_span = self.prev_token.span; self.psess.gated_spans.gate(sym::yield_expr, yield_span); - return Ok(self.mk_expr(yield_span, ExprKind::Yield(Some(self_arg)))); + return Ok( + self.mk_expr(yield_span, ExprKind::Yield(Some(self_arg), YieldKind::Postfix)) + ); } let fn_span_lo = self.token.span; @@ -1891,7 +1894,7 @@ impl<'a> Parser<'a> { /// Parse `"yield" expr?`. fn parse_expr_yield(&mut self) -> PResult<'a, P> { let lo = self.prev_token.span; - let kind = ExprKind::Yield(self.parse_expr_opt()?); + let kind = ExprKind::Yield(self.parse_expr_opt()?, YieldKind::Prefix); let span = lo.to(self.prev_token.span); self.psess.gated_spans.gate(sym::yield_expr, span); let expr = self.mk_expr(span, kind); @@ -4045,7 +4048,7 @@ impl MutVisitor for CondChecker<'_> { | ExprKind::MacCall(_) | ExprKind::Struct(_) | ExprKind::Repeat(_, _) - | ExprKind::Yield(_) + | ExprKind::Yield(_, _) | ExprKind::Yeet(_) | ExprKind::Become(_) | ExprKind::IncludedBytes(_) diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index fe716c186389f..bee391532294d 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -485,7 +485,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Index(_, ref expr, _) | ast::ExprKind::Unary(_, ref expr) | ast::ExprKind::Try(ref expr) - | ast::ExprKind::Yield(Some(ref expr)) => is_block_expr(context, expr, repr), + | ast::ExprKind::Yield(Some(ref expr), _) => is_block_expr(context, expr, repr), ast::ExprKind::Closure(ref closure) => is_block_expr(context, &closure.body, repr), // This can only be a string lit ast::ExprKind::Lit(_) => { @@ -515,7 +515,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Tup(..) | ast::ExprKind::Use(..) | ast::ExprKind::Type(..) - | ast::ExprKind::Yield(None) + | ast::ExprKind::Yield(None, _) | ast::ExprKind::Underscore => false, } } diff --git a/tests/pretty/postfix-yield.rs b/tests/pretty/postfix-yield.rs new file mode 100644 index 0000000000000..f76e8142ae86c --- /dev/null +++ b/tests/pretty/postfix-yield.rs @@ -0,0 +1,15 @@ +// This demonstrates a proposed alternate or additional option of having yield in postfix position. +//@ edition: 2024 +//@ pp-exact + +#![feature(gen_blocks, coroutines, coroutine_trait, yield_expr)] + +use std::ops::{Coroutine, CoroutineState}; +use std::pin::pin; + +fn main() { + let mut gn = gen { yield 1; 2.yield; (1 + 2).yield; }; + + let mut coro = + pin!(#[coroutine] |_: i32| { let x = 1.yield; (x + 2).yield; }); +} diff --git a/tests/ui/coroutine/postfix-yield.rs b/tests/ui/coroutine/postfix-yield.rs index 77b1c2a19d0a4..ff843138c8c2c 100644 --- a/tests/ui/coroutine/postfix-yield.rs +++ b/tests/ui/coroutine/postfix-yield.rs @@ -9,7 +9,7 @@ use std::ops::{Coroutine, CoroutineState}; use std::pin::pin; fn main() { - // generators (i.e. yield doesn't return anything useful) + // generators (i.e. yield doesn't return anything useful) let mut gn = gen { yield 1; 2.yield; @@ -23,8 +23,8 @@ fn main() { let mut coro = pin!( #[coroutine] |_: i32| { - let x = yield 1; - yield x + 2; + let x = 1.yield; + (x + 2).yield; } ); From 635eae2d4fc724cb53a3a45975bc18779a3293b1 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 13 Mar 2025 14:36:02 -0700 Subject: [PATCH 05/24] Teach rustfmt to handle postfix yield --- .../clippy/clippy_utils/src/ast_utils/mod.rs | 5 +++-- src/tools/rustfmt/src/expr.rs | 5 +++-- src/tools/rustfmt/tests/source/postfix-yield.rs | 15 +++++++++++++++ src/tools/rustfmt/tests/target/postfix-yield.rs | 12 ++++++++++++ 4 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 src/tools/rustfmt/tests/source/postfix-yield.rs create mode 100644 src/tools/rustfmt/tests/target/postfix-yield.rs diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 707312a97f3bc..deda6030831ec 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -201,7 +201,8 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lt, rt), (Block(lb, ll), Block(rb, rl)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lb, rb), (TryBlock(l), TryBlock(r)) => eq_block(l, r), - (Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l.as_ref(), r.as_ref()), + (Yield(l, lk), Yield(r, rk)) => eq_expr_opt(l.as_ref(), r.as_ref()) && lk == rk, + (Ret(l), Ret(r)) => eq_expr_opt(l.as_ref(), r.as_ref()), (Break(ll, le), Break(rl, re)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_expr_opt(le.as_ref(), re.as_ref()), (Continue(ll), Continue(rl)) => eq_label(ll.as_ref(), rl.as_ref()), (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2, _), Index(r1, r2, _)) => { @@ -688,7 +689,7 @@ pub fn eq_generics(l: &Generics, r: &Generics) -> bool { pub fn eq_where_predicate(l: &WherePredicate, r: &WherePredicate) -> bool { use WherePredicateKind::*; - over(&l.attrs, &r.attrs, eq_attr) + over(&l.attrs, &r.attrs, eq_attr) && match (&l.kind, &r.kind) { (BoundPredicate(l), BoundPredicate(r)) => { over(&l.bound_generic_params, &r.bound_generic_params, |l, r| { diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index eff2d2e3ff4a3..92c1ffa6076d3 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -221,7 +221,7 @@ pub(crate) fn format_expr( Ok(format!("break{id_str}")) } } - ast::ExprKind::Yield(ref opt_expr) => { + ast::ExprKind::Yield(ref opt_expr, ast::YieldKind::Prefix) => { if let Some(ref expr) = *opt_expr { rewrite_unary_prefix(context, "yield ", &**expr, shape) } else { @@ -243,7 +243,8 @@ pub(crate) fn format_expr( ast::ExprKind::Try(..) | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) - | ast::ExprKind::Await(_, _) => rewrite_chain(expr, context, shape), + | ast::ExprKind::Await(_, _) + | ast::ExprKind::Yield(_, ast::YieldKind::Postfix) => rewrite_chain(expr, context, shape), ast::ExprKind::MacCall(ref mac) => { rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|_| { wrap_str( diff --git a/src/tools/rustfmt/tests/source/postfix-yield.rs b/src/tools/rustfmt/tests/source/postfix-yield.rs new file mode 100644 index 0000000000000..8a8958f3ad4e8 --- /dev/null +++ b/src/tools/rustfmt/tests/source/postfix-yield.rs @@ -0,0 +1,15 @@ +// This demonstrates a proposed alternate or additional option of having yield in postfix position. +//@ edition: 2024 + +#![feature(gen_blocks, coroutines, coroutine_trait, yield_expr)] + +use std::ops::{Coroutine, CoroutineState}; +use std::pin::pin; + +fn main() { + let mut coro = + pin!(#[coroutine] |_: i32| { let x = 1.yield; + + + (x + 2).yield; }); +} diff --git a/src/tools/rustfmt/tests/target/postfix-yield.rs b/src/tools/rustfmt/tests/target/postfix-yield.rs new file mode 100644 index 0000000000000..7e94e1e095add --- /dev/null +++ b/src/tools/rustfmt/tests/target/postfix-yield.rs @@ -0,0 +1,12 @@ +// This demonstrates a proposed alternate or additional option of having yield in postfix position. +//@ edition: 2024 + +#![feature(gen_blocks, coroutines, coroutine_trait, yield_expr)] + +use std::ops::{Coroutine, CoroutineState}; +use std::pin::pin; + +fn main() { + let mut coro = + pin!(#[coroutine] |_: i32| { let x = 1.yield; (x + 2).yield; }); +} From c5093ac1224fe9eeff5c5694f1c3ff643005d7d4 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Thu, 13 Mar 2025 16:14:31 -0700 Subject: [PATCH 06/24] Fix clippy --- .../clippy/clippy_lints/src/suspicious_operation_groupings.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs index 0d809c17989de..206912d8de40d 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs @@ -528,7 +528,7 @@ fn ident_difference_expr_with_base_location( &strip_non_ident_wrappers(left).kind, &strip_non_ident_wrappers(right).kind, ) { - (Yield(_), Yield(_)) + (Yield(_, _), Yield(_, _)) | (Try(_), Try(_)) | (Paren(_), Paren(_)) | (Repeat(_, _), Repeat(_, _)) From b77590c1176839b127fe1f20b4557267d26d91a7 Mon Sep 17 00:00:00 2001 From: David Tenty Date: Mon, 17 Mar 2025 16:24:55 -0400 Subject: [PATCH 07/24] Use llvm_runtimes for compiler-rt --- src/bootstrap/src/core/build_steps/llvm.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 1e3148d631cb1..0b1799198daf5 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -479,7 +479,6 @@ impl Step for Llvm { if helpers::forcing_clang_based_tests() { enabled_llvm_projects.push("clang"); - enabled_llvm_projects.push("compiler-rt"); } if builder.config.llvm_polly { @@ -502,6 +501,10 @@ impl Step for Llvm { let mut enabled_llvm_runtimes = Vec::new(); + if helpers::forcing_clang_based_tests() { + enabled_llvm_runtimes.push("compiler-rt"); + } + if builder.config.llvm_offload { enabled_llvm_runtimes.push("offload"); //FIXME(ZuseZ4): LLVM intends to drop the offload dependency on openmp. From 636285180daa00b62a604acee9c843128d70262f Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Wed, 1 May 2024 18:32:45 -0500 Subject: [PATCH 08/24] [bootstrap] Distribute split debuginfo if present If debuginfo has been requested in `config.toml`, it should be packaged alongside the appropriate binary when running `x.py dist`. Currently, this is only implemented for msvc environments where split debuginfo is (basically) the only option. I've tested that this correctly packages the `.pdb` for each binary in the various dist packages. --- src/bootstrap/src/core/build_steps/compile.rs | 56 ++++--- src/bootstrap/src/core/build_steps/dist.rs | 155 ++++++++++++------ src/bootstrap/src/core/build_steps/doc.rs | 3 +- src/bootstrap/src/core/build_steps/tool.rs | 32 ++-- src/bootstrap/src/lib.rs | 63 ++++++- src/bootstrap/src/utils/helpers.rs | 17 ++ src/bootstrap/src/utils/tarball.rs | 28 +++- 7 files changed, 255 insertions(+), 99 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 846b4de81426e..18b5d4426b1ee 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -33,7 +33,7 @@ use crate::utils::exec::command; use crate::utils::helpers::{ exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date, }; -use crate::{CLang, Compiler, DependencyType, GitRepo, LLVM_TOOLS, Mode, debug, trace}; +use crate::{CLang, Compiler, DependencyType, FileType, GitRepo, LLVM_TOOLS, Mode, debug, trace}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Std { @@ -321,7 +321,7 @@ fn copy_and_stamp( dependency_type: DependencyType, ) { let target = libdir.join(name); - builder.copy_link(&sourcedir.join(name), &target); + builder.copy_link(&sourcedir.join(name), &target, FileType::Regular); target_deps.push((target, dependency_type)); } @@ -330,7 +330,7 @@ fn copy_llvm_libunwind(builder: &Builder<'_>, target: TargetSelection, libdir: & let libunwind_path = builder.ensure(llvm::Libunwind { target }); let libunwind_source = libunwind_path.join("libunwind.a"); let libunwind_target = libdir.join("libunwind.a"); - builder.copy_link(&libunwind_source, &libunwind_target); + builder.copy_link(&libunwind_source, &libunwind_target, FileType::NativeLibrary); libunwind_target } @@ -401,7 +401,7 @@ fn copy_self_contained_objects( for &obj in &["crtbegin.o", "crtbeginS.o", "crtend.o", "crtendS.o"] { let src = crt_path.join(obj); let target = libdir_self_contained.join(obj); - builder.copy_link(&src, &target); + builder.copy_link(&src, &target, FileType::NativeLibrary); target_deps.push((target, DependencyType::TargetSelfContained)); } } else { @@ -443,9 +443,9 @@ fn copy_self_contained_objects( } else if target.is_windows_gnu() { for obj in ["crt2.o", "dllcrt2.o"].iter() { let src = compiler_file(builder, &builder.cc(target), target, CLang::C, obj); - let target = libdir_self_contained.join(obj); - builder.copy_link(&src, &target); - target_deps.push((target, DependencyType::TargetSelfContained)); + let dst = libdir_self_contained.join(obj); + builder.copy_link(&src, &dst, FileType::NativeLibrary); + target_deps.push((dst, DependencyType::TargetSelfContained)); } } @@ -790,8 +790,11 @@ impl Step for StdLink { let file = t!(file); let path = file.path(); if path.is_file() { - builder - .copy_link(&path, &sysroot.join("lib").join(path.file_name().unwrap())); + builder.copy_link( + &path, + &sysroot.join("lib").join(path.file_name().unwrap()), + FileType::Regular, + ); } } } @@ -829,7 +832,7 @@ fn copy_sanitizers( for runtime in &runtimes { let dst = libdir.join(&runtime.name); - builder.copy_link(&runtime.path, &dst); + builder.copy_link(&runtime.path, &dst, FileType::NativeLibrary); // The `aarch64-apple-ios-macabi` and `x86_64-apple-ios-macabi` are also supported for // sanitizers, but they share a sanitizer runtime with `${arch}-apple-darwin`, so we do @@ -934,9 +937,9 @@ impl Step for StartupObjects { .run(builder); } - let target = sysroot_dir.join((*file).to_string() + ".o"); - builder.copy_link(dst_file, &target); - target_deps.push((target, DependencyType::Target)); + let obj = sysroot_dir.join((*file).to_string() + ".o"); + builder.copy_link(dst_file, &obj, FileType::NativeLibrary); + target_deps.push((obj, DependencyType::Target)); } target_deps @@ -952,7 +955,7 @@ fn cp_rustc_component_to_ci_sysroot(builder: &Builder<'_>, sysroot: &Path, conte if src.is_dir() { t!(fs::create_dir_all(dst)); } else { - builder.copy_link(&src, &dst); + builder.copy_link(&src, &dst, FileType::Regular); } } } @@ -1707,7 +1710,7 @@ fn copy_codegen_backends_to_sysroot( let dot = filename.find('.').unwrap(); format!("{}-{}{}", &filename[..dash], builder.rust_release(), &filename[dot..]) }; - builder.copy_link(file, &dst.join(target_filename)); + builder.copy_link(file, &dst.join(target_filename), FileType::NativeLibrary); } } @@ -2011,7 +2014,11 @@ impl Step for Assemble { extra_features: vec![], }); let tool_exe = exe("llvm-bitcode-linker", target_compiler.host); - builder.copy_link(&llvm_bitcode_linker.tool_path, &libdir_bin.join(tool_exe)); + builder.copy_link( + &llvm_bitcode_linker.tool_path, + &libdir_bin.join(tool_exe), + FileType::Executable, + ); } }; @@ -2072,8 +2079,8 @@ impl Step for Assemble { builder.sysroot_target_libdir(target_compiler, target_compiler.host); let dst_lib = libdir.join(&libenzyme).with_extension(lib_ext); let target_dst_lib = target_libdir.join(&libenzyme).with_extension(lib_ext); - builder.copy_link(&src_lib, &dst_lib); - builder.copy_link(&src_lib, &target_dst_lib); + builder.copy_link(&src_lib, &dst_lib, FileType::NativeLibrary); + builder.copy_link(&src_lib, &target_dst_lib, FileType::NativeLibrary); } // Build the libraries for this compiler to link to (i.e., the libraries @@ -2168,7 +2175,7 @@ impl Step for Assemble { }; if is_dylib_or_debug && can_be_rustc_dynamic_dep && !is_proc_macro { - builder.copy_link(&f.path(), &rustc_libdir.join(&filename)); + builder.copy_link(&f.path(), &rustc_libdir.join(&filename), FileType::Regular); } } @@ -2196,7 +2203,11 @@ impl Step for Assemble { // See . let src_exe = exe("llvm-objcopy", target_compiler.host); let dst_exe = exe("rust-objcopy", target_compiler.host); - builder.copy_link(&libdir_bin.join(src_exe), &libdir_bin.join(dst_exe)); + builder.copy_link( + &libdir_bin.join(src_exe), + &libdir_bin.join(dst_exe), + FileType::Executable, + ); } // In addition to `rust-lld` also install `wasm-component-ld` when @@ -2212,6 +2223,7 @@ impl Step for Assemble { builder.copy_link( &wasm_component.tool_path, &libdir_bin.join(wasm_component.tool_path.file_name().unwrap()), + FileType::Executable, ); } @@ -2234,7 +2246,7 @@ impl Step for Assemble { t!(fs::create_dir_all(bindir)); let compiler = builder.rustc(target_compiler); debug!(src = ?rustc, dst = ?compiler, "linking compiler binary itself"); - builder.copy_link(&rustc, &compiler); + builder.copy_link(&rustc, &compiler, FileType::Executable); target_compiler } @@ -2260,7 +2272,7 @@ pub fn add_to_sysroot( DependencyType::Target => sysroot_dst, DependencyType::TargetSelfContained => self_contained_dst, }; - builder.copy_link(&path, &dst.join(path.file_name().unwrap())); + builder.copy_link(&path, &dst.join(path.file_name().unwrap()), FileType::Regular); } } diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 39f9680cb2f6f..3305b7c2d3627 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -32,7 +32,7 @@ use crate::utils::helpers::{ exe, is_dylib, move_file, t, target_supports_cranelift_backend, timeit, }; use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball}; -use crate::{Compiler, DependencyType, LLVM_TOOLS, Mode, trace}; +use crate::{Compiler, DependencyType, FileType, LLVM_TOOLS, Mode, trace}; pub fn pkgname(builder: &Builder<'_>, component: &str) -> String { format!("{}-{}", component, builder.rust_package_vers()) @@ -81,7 +81,7 @@ impl Step for Docs { let mut tarball = Tarball::new(builder, "rust-docs", &host.triple); tarball.set_product_name("Rust Documentation"); tarball.add_bulk_dir(builder.doc_out(host), dest); - tarball.add_file(builder.src.join("src/doc/robots.txt"), dest, 0o644); + tarball.add_file(builder.src.join("src/doc/robots.txt"), dest, FileType::Regular); Some(tarball.generate()) } } @@ -418,7 +418,7 @@ impl Step for Rustc { .is_none_or(|tools| tools.iter().any(|tool| tool == "rustdoc")) { let rustdoc = builder.rustdoc(compiler); - builder.install(&rustdoc, &image.join("bin"), 0o755); + builder.install(&rustdoc, &image.join("bin"), FileType::Executable); } if let Some(ra_proc_macro_srv) = builder.ensure_if_default( @@ -432,7 +432,8 @@ impl Step for Rustc { }, builder.kind, ) { - builder.install(&ra_proc_macro_srv.tool_path, &image.join("libexec"), 0o755); + let dst = image.join("libexec"); + builder.install(&ra_proc_macro_srv.tool_path, &dst, FileType::Executable); } let libdir_relative = builder.libdir_relative(compiler); @@ -444,7 +445,7 @@ impl Step for Rustc { if is_dylib(&entry.path()) { // Don't use custom libdir here because ^lib/ will be resolved again // with installer - builder.install(&entry.path(), &image.join("lib"), 0o644); + builder.install(&entry.path(), &image.join("lib"), FileType::NativeLibrary); } } } @@ -463,7 +464,11 @@ impl Step for Rustc { if builder.config.lld_enabled { let src_dir = builder.sysroot_target_bindir(compiler, host); let rust_lld = exe("rust-lld", compiler.host); - builder.copy_link(&src_dir.join(&rust_lld), &dst_dir.join(&rust_lld)); + builder.copy_link( + &src_dir.join(&rust_lld), + &dst_dir.join(&rust_lld), + FileType::Executable, + ); let self_contained_lld_src_dir = src_dir.join("gcc-ld"); let self_contained_lld_dst_dir = dst_dir.join("gcc-ld"); t!(fs::create_dir(&self_contained_lld_dst_dir)); @@ -472,6 +477,7 @@ impl Step for Rustc { builder.copy_link( &self_contained_lld_src_dir.join(&exe_name), &self_contained_lld_dst_dir.join(&exe_name), + FileType::Executable, ); } } @@ -480,13 +486,17 @@ impl Step for Rustc { let src_dir = builder.sysroot_target_bindir(compiler, host); let llvm_objcopy = exe("llvm-objcopy", compiler.host); let rust_objcopy = exe("rust-objcopy", compiler.host); - builder.copy_link(&src_dir.join(&llvm_objcopy), &dst_dir.join(&rust_objcopy)); + builder.copy_link( + &src_dir.join(&llvm_objcopy), + &dst_dir.join(&rust_objcopy), + FileType::Executable, + ); } if builder.tool_enabled("wasm-component-ld") { let src_dir = builder.sysroot_target_bindir(compiler, host); let ld = exe("wasm-component-ld", compiler.host); - builder.copy_link(&src_dir.join(&ld), &dst_dir.join(&ld)); + builder.copy_link(&src_dir.join(&ld), &dst_dir.join(&ld), FileType::Executable); } // Man pages @@ -511,15 +521,19 @@ impl Step for Rustc { // HTML copyright files let file_list = builder.ensure(super::run::GenerateCopyright); for file in file_list { - builder.install(&file, &image.join("share/doc/rust"), 0o644); + builder.install(&file, &image.join("share/doc/rust"), FileType::Regular); } // README - builder.install(&builder.src.join("README.md"), &image.join("share/doc/rust"), 0o644); + builder.install( + &builder.src.join("README.md"), + &image.join("share/doc/rust"), + FileType::Regular, + ); // The REUSE-managed license files let license = |path: &Path| { - builder.install(path, &image.join("share/doc/rust/licenses"), 0o644); + builder.install(path, &image.join("share/doc/rust/licenses"), FileType::Regular); }; for entry in t!(std::fs::read_dir(builder.src.join("LICENSES"))).flatten() { license(&entry.path()); @@ -548,14 +562,14 @@ impl Step for DebuggerScripts { let dst = sysroot.join("lib/rustlib/etc"); t!(fs::create_dir_all(&dst)); let cp_debugger_script = |file: &str| { - builder.install(&builder.src.join("src/etc/").join(file), &dst, 0o644); + builder.install(&builder.src.join("src/etc/").join(file), &dst, FileType::Regular); }; if host.contains("windows-msvc") { // windbg debugger scripts builder.install( &builder.src.join("src/etc/rust-windbg.cmd"), &sysroot.join("bin"), - 0o755, + FileType::Script, ); cp_debugger_script("natvis/intrinsic.natvis"); @@ -567,15 +581,27 @@ impl Step for DebuggerScripts { cp_debugger_script("rust_types.py"); // gdb debugger scripts - builder.install(&builder.src.join("src/etc/rust-gdb"), &sysroot.join("bin"), 0o755); - builder.install(&builder.src.join("src/etc/rust-gdbgui"), &sysroot.join("bin"), 0o755); + builder.install( + &builder.src.join("src/etc/rust-gdb"), + &sysroot.join("bin"), + FileType::Script, + ); + builder.install( + &builder.src.join("src/etc/rust-gdbgui"), + &sysroot.join("bin"), + FileType::Script, + ); cp_debugger_script("gdb_load_rust_pretty_printers.py"); cp_debugger_script("gdb_lookup.py"); cp_debugger_script("gdb_providers.py"); // lldb debugger scripts - builder.install(&builder.src.join("src/etc/rust-lldb"), &sysroot.join("bin"), 0o755); + builder.install( + &builder.src.join("src/etc/rust-lldb"), + &sysroot.join("bin"), + FileType::Script, + ); cp_debugger_script("lldb_lookup.py"); cp_debugger_script("lldb_providers.py"); @@ -640,9 +666,13 @@ fn copy_target_libs( t!(fs::create_dir_all(&self_contained_dst)); for (path, dependency_type) in builder.read_stamp_file(stamp) { if dependency_type == DependencyType::TargetSelfContained { - builder.copy_link(&path, &self_contained_dst.join(path.file_name().unwrap())); + builder.copy_link( + &path, + &self_contained_dst.join(path.file_name().unwrap()), + FileType::NativeLibrary, + ); } else if dependency_type == DependencyType::Target || builder.is_builder_target(target) { - builder.copy_link(&path, &dst.join(path.file_name().unwrap())); + builder.copy_link(&path, &dst.join(path.file_name().unwrap()), FileType::NativeLibrary); } } } @@ -750,7 +780,11 @@ impl Step for RustcDev { &tarball.image_dir().join("lib/rustlib/rustc-src/rust"), ); for file in src_files { - tarball.add_file(builder.src.join(file), "lib/rustlib/rustc-src/rust", 0o644); + tarball.add_file( + builder.src.join(file), + "lib/rustlib/rustc-src/rust", + FileType::Regular, + ); } Some(tarball.generate()) @@ -1045,7 +1079,11 @@ impl Step for PlainSourceTarball { // Copy the files normally for item in &src_files { - builder.copy_link(&builder.src.join(item), &plain_dst_src.join(item)); + builder.copy_link( + &builder.src.join(item), + &plain_dst_src.join(item), + FileType::Regular, + ); } // Create the version file @@ -1147,9 +1185,14 @@ impl Step for Cargo { let mut tarball = Tarball::new(builder, "cargo", &target.triple); tarball.set_overlay(OverlayKind::Cargo); - tarball.add_file(cargo.tool_path, "bin", 0o755); - tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", 0o644); - tarball.add_renamed_file(etc.join("cargo.bashcomp.sh"), "etc/bash_completion.d", "cargo"); + tarball.add_file(&cargo.tool_path, "bin", FileType::Executable); + tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", FileType::Regular); + tarball.add_renamed_file( + etc.join("cargo.bashcomp.sh"), + "etc/bash_completion.d", + "cargo", + FileType::Regular, + ); tarball.add_dir(etc.join("man"), "share/man/man1"); tarball.add_legal_and_readme_to("share/doc/cargo"); @@ -1193,7 +1236,7 @@ impl Step for RustAnalyzer { let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple); tarball.set_overlay(OverlayKind::RustAnalyzer); tarball.is_preview(true); - tarball.add_file(rust_analyzer.tool_path, "bin", 0o755); + tarball.add_file(&rust_analyzer.tool_path, "bin", FileType::Executable); tarball.add_legal_and_readme_to("share/doc/rust-analyzer"); Some(tarball.generate()) } @@ -1239,8 +1282,8 @@ impl Step for Clippy { let mut tarball = Tarball::new(builder, "clippy", &target.triple); tarball.set_overlay(OverlayKind::Clippy); tarball.is_preview(true); - tarball.add_file(clippy.tool_path, "bin", 0o755); - tarball.add_file(cargoclippy.tool_path, "bin", 0o755); + tarball.add_file(&clippy.tool_path, "bin", FileType::Executable); + tarball.add_file(&cargoclippy.tool_path, "bin", FileType::Executable); tarball.add_legal_and_readme_to("share/doc/clippy"); Some(tarball.generate()) } @@ -1289,8 +1332,8 @@ impl Step for Miri { let mut tarball = Tarball::new(builder, "miri", &target.triple); tarball.set_overlay(OverlayKind::Miri); tarball.is_preview(true); - tarball.add_file(miri.tool_path, "bin", 0o755); - tarball.add_file(cargomiri.tool_path, "bin", 0o755); + tarball.add_file(&miri.tool_path, "bin", FileType::Executable); + tarball.add_file(&cargomiri.tool_path, "bin", FileType::Executable); tarball.add_legal_and_readme_to("share/doc/miri"); Some(tarball.generate()) } @@ -1374,7 +1417,11 @@ impl Step for CodegenBackend { for backend in fs::read_dir(&backends_src).unwrap() { let file_name = backend.unwrap().file_name(); if file_name.to_str().unwrap().contains(&backend_name) { - tarball.add_file(backends_src.join(file_name), &backends_dst, 0o644); + tarball.add_file( + backends_src.join(file_name), + &backends_dst, + FileType::NativeLibrary, + ); found_backend = true; } } @@ -1420,8 +1467,8 @@ impl Step for Rustfmt { let mut tarball = Tarball::new(builder, "rustfmt", &target.triple); tarball.set_overlay(OverlayKind::Rustfmt); tarball.is_preview(true); - tarball.add_file(rustfmt.tool_path, "bin", 0o755); - tarball.add_file(cargofmt.tool_path, "bin", 0o755); + tarball.add_file(&rustfmt.tool_path, "bin", FileType::Executable); + tarball.add_file(&cargofmt.tool_path, "bin", FileType::Executable); tarball.add_legal_and_readme_to("share/doc/rustfmt"); Some(tarball.generate()) } @@ -1578,7 +1625,7 @@ impl Step for Extended { &work.join(format!("{}-{}", pkgname(builder, name), target.triple)), &pkg.join(name), ); - builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755); + builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), FileType::Script); pkgbuild(name); }; prepare("rustc"); @@ -1593,12 +1640,12 @@ impl Step for Extended { } } // create an 'uninstall' package - builder.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755); + builder.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), FileType::Script); pkgbuild("uninstall"); builder.create_dir(&pkg.join("res")); builder.create(&pkg.join("res/LICENSE.txt"), &license); - builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644); + builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), FileType::Regular); let mut cmd = command("productbuild"); cmd.arg("--distribution") .arg(xform(&etc.join("pkg/Distribution.xml"))) @@ -1655,7 +1702,7 @@ impl Step for Extended { prepare("rust-mingw"); } - builder.install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644); + builder.install(&etc.join("gfx/rust-logo.ico"), &exe, FileType::Regular); // Generate msi installer let wix_path = env::var_os("WIX") @@ -1874,8 +1921,8 @@ impl Step for Extended { } builder.create(&exe.join("LICENSE.rtf"), &rtf); - builder.install(&etc.join("gfx/banner.bmp"), &exe, 0o644); - builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644); + builder.install(&etc.join("gfx/banner.bmp"), &exe, FileType::Regular); + builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, FileType::Regular); builder.info(&format!("building `msi` installer with {light:?}")); let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target.triple); @@ -1961,13 +2008,13 @@ fn install_llvm_file( if source.is_symlink() { // If we have a symlink like libLLVM-18.so -> libLLVM.so.18.1, install the target of the // symlink, which is what will actually get loaded at runtime. - builder.install(&t!(fs::canonicalize(source)), destination, 0o644); + builder.install(&t!(fs::canonicalize(source)), destination, FileType::NativeLibrary); let full_dest = destination.join(source.file_name().unwrap()); if install_symlink { // For download-ci-llvm, also install the symlink, to match what LLVM does. Using a // symlink is fine here, as this is not a rustup component. - builder.copy_link(source, &full_dest); + builder.copy_link(source, &full_dest, FileType::NativeLibrary); } else { // Otherwise, replace the symlink with an equivalent linker script. This is used when // projects like miri link against librustc_driver.so. We don't use a symlink, as @@ -1984,7 +2031,7 @@ fn install_llvm_file( } } } else { - builder.install(source, destination, 0o644); + builder.install(source, destination, FileType::NativeLibrary); } } @@ -2036,7 +2083,7 @@ fn maybe_install_llvm( let src_libdir = builder.llvm_out(target).join("lib"); let llvm_dylib_path = src_libdir.join("libLLVM.dylib"); if llvm_dylib_path.exists() { - builder.install(&llvm_dylib_path, dst_libdir, 0o644); + builder.install(&llvm_dylib_path, dst_libdir, FileType::NativeLibrary); } !builder.config.dry_run() } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult { llvm_config, .. }) = @@ -2186,7 +2233,7 @@ impl Step for LlvmTools { let dst_bindir = format!("lib/rustlib/{}/bin", target.triple); for tool in tools_to_install(&builder.paths) { let exe = src_bindir.join(exe(tool, target)); - tarball.add_file(&exe, &dst_bindir, 0o755); + tarball.add_file(&exe, &dst_bindir, FileType::Executable); } } @@ -2241,7 +2288,7 @@ impl Step for LlvmBitcodeLinker { tarball.set_overlay(OverlayKind::LlvmBitcodeLinker); tarball.is_preview(true); - tarball.add_file(llbc_linker.tool_path, self_contained_bin_dir, 0o755); + tarball.add_file(&llbc_linker.tool_path, self_contained_bin_dir, FileType::Executable); Some(tarball.generate()) } @@ -2302,7 +2349,7 @@ impl Step for RustDev { let entry = t!(entry); if entry.file_type().is_file() && !entry.path_is_symlink() { let name = entry.file_name().to_str().unwrap(); - tarball.add_file(src_bindir.join(name), "bin", 0o755); + tarball.add_file(src_bindir.join(name), "bin", FileType::Executable); } } } @@ -2314,11 +2361,11 @@ impl Step for RustDev { // We don't build LLD on some platforms, so only add it if it exists let lld_path = lld_out.join("bin").join(exe("lld", target)); if lld_path.exists() { - tarball.add_file(lld_path, "bin", 0o755); + tarball.add_file(&lld_path, "bin", FileType::Executable); } } - tarball.add_file(builder.llvm_filecheck(target), "bin", 0o755); + tarball.add_file(builder.llvm_filecheck(target), "bin", FileType::Executable); // Copy the include directory as well; needed mostly to build // librustc_llvm properly (e.g., llvm-config.h is in here). But also @@ -2379,7 +2426,11 @@ impl Step for Bootstrap { let bootstrap_outdir = &builder.bootstrap_out; for file in &["bootstrap", "rustc", "rustdoc"] { - tarball.add_file(bootstrap_outdir.join(exe(file, target)), "bootstrap/bin", 0o755); + tarball.add_file( + bootstrap_outdir.join(exe(file, target)), + "bootstrap/bin", + FileType::Executable, + ); } Some(tarball.generate()) @@ -2412,7 +2463,7 @@ impl Step for BuildManifest { let build_manifest = builder.tool_exe(Tool::BuildManifest); let tarball = Tarball::new(builder, "build-manifest", &self.target.triple); - tarball.add_file(build_manifest, "bin", 0o755); + tarball.add_file(&build_manifest, "bin", FileType::Executable); tarball.generate() } } @@ -2444,15 +2495,15 @@ impl Step for ReproducibleArtifacts { let mut added_anything = false; let tarball = Tarball::new(builder, "reproducible-artifacts", &self.target.triple); if let Some(path) = builder.config.rust_profile_use.as_ref() { - tarball.add_file(path, ".", 0o644); + tarball.add_file(path, ".", FileType::Regular); added_anything = true; } if let Some(path) = builder.config.llvm_profile_use.as_ref() { - tarball.add_file(path, ".", 0o644); + tarball.add_file(path, ".", FileType::Regular); added_anything = true; } for profile in &builder.config.reproducible_artifacts { - tarball.add_file(profile, ".", 0o644); + tarball.add_file(profile, ".", FileType::Regular); added_anything = true; } if added_anything { Some(tarball.generate()) } else { None } @@ -2481,7 +2532,7 @@ impl Step for Gcc { fn run(self, builder: &Builder<'_>) -> Self::Output { let tarball = Tarball::new(builder, "gcc", &self.target.triple); let output = builder.ensure(super::gcc::Gcc { target: self.target }); - tarball.add_file(output.libgccjit, "lib", 0o644); + tarball.add_file(&output.libgccjit, "lib", FileType::NativeLibrary); tarball.generate() } } diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index a8da414610064..7fccf85a0ea9f 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -11,7 +11,6 @@ use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::{env, fs, mem}; -use crate::Mode; use crate::core::build_steps::compile; use crate::core::build_steps::tool::{self, SourceType, Tool, prepare_tool_cargo}; use crate::core::builder::{ @@ -19,6 +18,7 @@ use crate::core::builder::{ }; use crate::core::config::{Config, TargetSelection}; use crate::helpers::{submodule_path_of, symlink_dir, t, up_to_date}; +use crate::{FileType, Mode}; macro_rules! book { ($($name:ident, $path:expr, $book_name:expr, $lang:expr ;)+) => { @@ -546,6 +546,7 @@ impl Step for SharedAssets { builder.copy_link( &builder.src.join("src").join("doc").join("rust.css"), &out.join("rust.css"), + FileType::Regular, ); SharedAssetsPaths { version_info } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index aaf6712102cfc..cd57e06ae04a3 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -26,7 +26,7 @@ use crate::core::config::{DebuginfoLevel, RustcLto, TargetSelection}; use crate::utils::channel::GitInfo; use crate::utils::exec::{BootstrapCommand, command}; use crate::utils::helpers::{add_dylib_path, exe, t}; -use crate::{Compiler, Kind, Mode, gha}; +use crate::{Compiler, FileType, Kind, Mode, gha}; #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub enum SourceType { @@ -353,7 +353,7 @@ fn copy_link_tool_bin( ) -> PathBuf { let cargo_out = builder.cargo_out(compiler, mode, target).join(exe(name, target)); let bin = builder.tools_dir(compiler).join(exe(name, target)); - builder.copy_link(&cargo_out, &bin); + builder.copy_link(&cargo_out, &bin, FileType::Executable); bin } @@ -696,7 +696,7 @@ impl Step for Rustdoc { .join(exe("rustdoc", target_compiler.host)); let bin_rustdoc = bin_rustdoc(); - builder.copy_link(&precompiled_rustdoc, &bin_rustdoc); + builder.copy_link(&precompiled_rustdoc, &bin_rustdoc, FileType::Executable); return ToolBuildResult { tool_path: bin_rustdoc, @@ -743,7 +743,7 @@ impl Step for Rustdoc { compile::strip_debug(builder, target, &tool_path); } let bin_rustdoc = bin_rustdoc(); - builder.copy_link(&tool_path, &bin_rustdoc); + builder.copy_link(&tool_path, &bin_rustdoc, FileType::Executable); ToolBuildResult { tool_path: bin_rustdoc, build_compiler, target_compiler } } else { ToolBuildResult { tool_path, build_compiler, target_compiler } @@ -846,13 +846,20 @@ impl Step for LldWrapper { let src_exe = exe("lld", target); let dst_exe = exe("rust-lld", target); - builder.copy_link(&lld_install.join("bin").join(src_exe), &libdir_bin.join(dst_exe)); + builder.copy_link( + &lld_install.join("bin").join(src_exe), + &libdir_bin.join(dst_exe), + FileType::Executable, + ); let self_contained_lld_dir = libdir_bin.join("gcc-ld"); t!(fs::create_dir_all(&self_contained_lld_dir)); for name in crate::LLD_FILE_NAMES { - builder - .copy_link(&tool_result.tool_path, &self_contained_lld_dir.join(exe(name, target))); + builder.copy_link( + &tool_result.tool_path, + &self_contained_lld_dir.join(exe(name, target)), + FileType::Executable, + ); } tool_result @@ -949,8 +956,11 @@ impl Step for RustAnalyzerProcMacroSrv { // so that r-a can use it. let libexec_path = builder.sysroot(self.compiler).join("libexec"); t!(fs::create_dir_all(&libexec_path)); - builder - .copy_link(&tool_result.tool_path, &libexec_path.join("rust-analyzer-proc-macro-srv")); + builder.copy_link( + &tool_result.tool_path, + &libexec_path.join("rust-analyzer-proc-macro-srv"), + FileType::Executable, + ); Some(tool_result) } @@ -1007,7 +1017,7 @@ impl Step for LlvmBitcodeLinker { t!(fs::create_dir_all(&bindir_self_contained)); let bin_destination = bindir_self_contained .join(exe("llvm-bitcode-linker", tool_result.target_compiler.host)); - builder.copy_link(&tool_result.tool_path, &bin_destination); + builder.copy_link(&tool_result.tool_path, &bin_destination, FileType::Executable); ToolBuildResult { tool_path: bin_destination, build_compiler: tool_result.build_compiler, @@ -1189,7 +1199,7 @@ fn run_tool_build_step( for add_bin in add_bins_to_sysroot { let bin_destination = bindir.join(exe(add_bin, target_compiler.host)); - builder.copy_link(&tool_path, &bin_destination); + builder.copy_link(&tool_path, &bin_destination, FileType::Executable); } // Return a path into the bin dir. diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 1943d0299b9e7..a47b7a27790bb 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -36,7 +36,9 @@ use crate::core::builder; use crate::core::builder::Kind; use crate::core::config::{DryRun, LldMode, LlvmLibunwind, Target, TargetSelection, flags}; use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode, command}; -use crate::utils::helpers::{self, dir_is_empty, exe, libdir, output, set_file_times, symlink_dir}; +use crate::utils::helpers::{ + self, dir_is_empty, exe, libdir, output, set_file_times, split_debuginfo, symlink_dir, +}; mod core; mod utils; @@ -274,6 +276,35 @@ pub enum CLang { Cxx, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum FileType { + /// An executable binary file (like a `.exe`). + Executable, + /// A native, binary library file (like a `.so`, `.dll`, `.a`, `.lib` or `.o`). + NativeLibrary, + /// An executable (non-binary) script file (like a `.py` or `.sh`). + Script, + /// Any other regular file that is non-executable. + Regular, +} + +impl FileType { + /// Get Unix permissions appropriate for this file type. + pub fn perms(self) -> u32 { + match self { + FileType::Executable | FileType::Script => 0o755, + FileType::Regular | FileType::NativeLibrary => 0o644, + } + } + + pub fn could_have_split_debuginfo(self) -> bool { + match self { + FileType::Executable | FileType::NativeLibrary => true, + FileType::Script | FileType::Regular => false, + } + } +} + macro_rules! forward { ( $( $fn:ident( $($param:ident: $ty:ty),* ) $( -> $ret:ty)? ),+ $(,)? ) => { impl Build { @@ -1744,8 +1775,18 @@ Executed at: {executed_at}"#, /// Attempts to use hard links if possible, falling back to copying. /// You can neither rely on this being a copy nor it being a link, /// so do not write to dst. - pub fn copy_link(&self, src: &Path, dst: &Path) { + pub fn copy_link(&self, src: &Path, dst: &Path, file_type: FileType) { self.copy_link_internal(src, dst, false); + + if file_type.could_have_split_debuginfo() { + if let Some(dbg_file) = split_debuginfo(src) { + self.copy_link_internal( + &dbg_file, + &dst.with_extension(dbg_file.extension().unwrap()), + false, + ); + } + } } fn copy_link_internal(&self, src: &Path, dst: &Path, dereference_symlinks: bool) { @@ -1808,7 +1849,7 @@ Executed at: {executed_at}"#, t!(fs::create_dir_all(&dst)); self.cp_link_r(&path, &dst); } else { - self.copy_link(&path, &dst); + self.copy_link(&path, &dst, FileType::Regular); } } } @@ -1844,7 +1885,7 @@ Executed at: {executed_at}"#, self.cp_link_filtered_recurse(&path, &dst, &relative, filter); } else { let _ = fs::remove_file(&dst); - self.copy_link(&path, &dst); + self.copy_link(&path, &dst, FileType::Regular); } } } @@ -1853,10 +1894,10 @@ Executed at: {executed_at}"#, fn copy_link_to_folder(&self, src: &Path, dest_folder: &Path) { let file_name = src.file_name().unwrap(); let dest = dest_folder.join(file_name); - self.copy_link(src, &dest); + self.copy_link(src, &dest, FileType::Regular); } - fn install(&self, src: &Path, dstdir: &Path, perms: u32) { + fn install(&self, src: &Path, dstdir: &Path, file_type: FileType) { if self.config.dry_run() { return; } @@ -1866,8 +1907,16 @@ Executed at: {executed_at}"#, if !src.exists() { panic!("ERROR: File \"{}\" not found!", src.display()); } + self.copy_link_internal(src, &dst, true); - chmod(&dst, perms); + chmod(&dst, file_type.perms()); + + // If this file can have debuginfo, look for split debuginfo and install it too. + if file_type.could_have_split_debuginfo() { + if let Some(dbg_file) = split_debuginfo(src) { + self.install(&dbg_file, dstdir, FileType::Regular); + } + } } fn read(&self, path: &Path) -> String { diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 89d93a29acbca..f8e4d4e04717d 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -52,6 +52,23 @@ pub fn exe(name: &str, target: TargetSelection) -> String { crate::utils::shared_helpers::exe(name, &target.triple) } +/// Returns the path to the split debug info for the specified file if it exists. +pub fn split_debuginfo(name: impl Into) -> Option { + // FIXME: only msvc is currently supported + + let path = name.into(); + let pdb = path.with_extension("pdb"); + if pdb.exists() { + return Some(pdb); + } + + // pdbs get named with '-' replaced by '_' + let file_name = pdb.file_name()?.to_str()?.replace("-", "_"); + + let pdb: PathBuf = [path.parent()?, Path::new(&file_name)].into_iter().collect(); + pdb.exists().then_some(pdb) +} + /// Returns `true` if the file name given looks like a dynamic library. pub fn is_dylib(path: &Path) -> bool { path.extension().and_then(|ext| ext.to_str()).is_some_and(|ext| { diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index f1678bacc9769..7b77b21293413 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -7,6 +7,7 @@ use std::path::{Path, PathBuf}; +use crate::FileType; use crate::core::build_steps::dist::distdir; use crate::core::builder::{Builder, Kind}; use crate::core::config::BUILDER_CONFIG_FILENAME; @@ -182,7 +183,12 @@ impl<'a> Tarball<'a> { &self.image_dir } - pub(crate) fn add_file(&self, src: impl AsRef, destdir: impl AsRef, perms: u32) { + pub(crate) fn add_file( + &self, + src: impl AsRef, + destdir: impl AsRef, + file_type: FileType, + ) { // create_dir_all fails to create `foo/bar/.`, so when the destination is "." this simply // uses the base directory as the destination directory. let destdir = if destdir.as_ref() == Path::new(".") { @@ -192,7 +198,7 @@ impl<'a> Tarball<'a> { }; t!(std::fs::create_dir_all(&destdir)); - self.builder.install(src.as_ref(), &destdir, perms); + self.builder.install(src.as_ref(), &destdir, file_type); } pub(crate) fn add_renamed_file( @@ -200,15 +206,16 @@ impl<'a> Tarball<'a> { src: impl AsRef, destdir: impl AsRef, new_name: &str, + file_type: FileType, ) { let destdir = self.image_dir.join(destdir.as_ref()); t!(std::fs::create_dir_all(&destdir)); - self.builder.copy_link(src.as_ref(), &destdir.join(new_name)); + self.builder.copy_link(src.as_ref(), &destdir.join(new_name), file_type); } pub(crate) fn add_legal_and_readme_to(&self, destdir: impl AsRef) { for file in self.overlay.legal_and_readme() { - self.add_file(self.builder.src.join(file), destdir.as_ref(), 0o644); + self.add_file(self.builder.src.join(file), destdir.as_ref(), FileType::Regular); } } @@ -318,11 +325,20 @@ impl<'a> Tarball<'a> { // Add config file if present. if let Some(config) = &self.builder.config.config { - self.add_renamed_file(config, &self.overlay_dir, BUILDER_CONFIG_FILENAME); + self.add_renamed_file( + config, + &self.overlay_dir, + BUILDER_CONFIG_FILENAME, + FileType::Regular, + ); } for file in self.overlay.legal_and_readme() { - self.builder.install(&self.builder.src.join(file), &self.overlay_dir, 0o644); + self.builder.install( + &self.builder.src.join(file), + &self.overlay_dir, + FileType::Regular, + ); } let mut cmd = self.builder.tool_cmd(crate::core::build_steps::tool::Tool::RustInstaller); From 9b0e7f62644b629c30b4157ad854296eca36ecf0 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Mon, 17 Mar 2025 17:32:11 -0700 Subject: [PATCH 09/24] Teach rustfmt to handle postfix yield This involved fixing the span when parsing .yield --- compiler/rustc_parse/src/parser/expr.rs | 5 ++--- src/tools/rustfmt/src/chains.rs | 10 +++++++++- src/tools/rustfmt/src/utils.rs | 8 +++++--- src/tools/rustfmt/tests/source/postfix-yield.rs | 15 --------------- src/tools/rustfmt/tests/target/postfix-yield.rs | 9 +++++++-- 5 files changed, 23 insertions(+), 24 deletions(-) delete mode 100644 src/tools/rustfmt/tests/source/postfix-yield.rs diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index cb04bbc240e49..28d100074f3eb 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1315,9 +1315,8 @@ impl<'a> Parser<'a> { if self.eat_keyword(exp!(Yield)) { let yield_span = self.prev_token.span; self.psess.gated_spans.gate(sym::yield_expr, yield_span); - return Ok( - self.mk_expr(yield_span, ExprKind::Yield(Some(self_arg), YieldKind::Postfix)) - ); + return Ok(self + .mk_expr(lo.to(yield_span), ExprKind::Yield(Some(self_arg), YieldKind::Postfix))); } let fn_span_lo = self.token.span; diff --git a/src/tools/rustfmt/src/chains.rs b/src/tools/rustfmt/src/chains.rs index fd2ef9cb1db9d..fabb44005532d 100644 --- a/src/tools/rustfmt/src/chains.rs +++ b/src/tools/rustfmt/src/chains.rs @@ -192,6 +192,7 @@ enum ChainItemKind { StructField(symbol::Ident), TupleField(symbol::Ident, bool), Await, + Yield, Comment(String, CommentPosition), } @@ -203,6 +204,7 @@ impl ChainItemKind { | ChainItemKind::StructField(..) | ChainItemKind::TupleField(..) | ChainItemKind::Await + | ChainItemKind::Yield | ChainItemKind::Comment(..) => false, } } @@ -257,6 +259,10 @@ impl ChainItemKind { let span = mk_sp(nested.span.hi(), expr.span.hi()); (ChainItemKind::Await, span) } + ast::ExprKind::Yield(Some(ref nested), ast::YieldKind::Postfix) => { + let span = mk_sp(nested.span.hi(), expr.span.hi()); + (ChainItemKind::Yield, span) + } _ => { return ( ChainItemKind::Parent { @@ -306,6 +312,7 @@ impl Rewrite for ChainItem { rewrite_ident(context, ident) ), ChainItemKind::Await => ".await".to_owned(), + ChainItemKind::Yield => ".yield".to_owned(), ChainItemKind::Comment(ref comment, _) => { rewrite_comment(comment, false, shape, context.config)? } @@ -508,7 +515,8 @@ impl Chain { }), ast::ExprKind::Field(ref subexpr, _) | ast::ExprKind::Try(ref subexpr) - | ast::ExprKind::Await(ref subexpr, _) => Some(SubExpr { + | ast::ExprKind::Await(ref subexpr, _) + | ast::ExprKind::Yield(Some(ref subexpr), ast::YieldKind::Postfix) => Some(SubExpr { expr: Self::convert_try(subexpr, context), is_method_call_receiver: false, }), diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index bee391532294d..1811752c3c439 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{ self, Attribute, MetaItem, MetaItemInner, MetaItemKind, NodeId, Path, Visibility, VisibilityKind, }; -use rustc_ast::ptr; +use rustc_ast::{YieldKind, ptr}; use rustc_ast_pretty::pprust; use rustc_span::{BytePos, LocalExpnId, Span, Symbol, SyntaxContext, sym, symbol}; use unicode_width::UnicodeWidthStr; @@ -485,7 +485,9 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Index(_, ref expr, _) | ast::ExprKind::Unary(_, ref expr) | ast::ExprKind::Try(ref expr) - | ast::ExprKind::Yield(Some(ref expr), _) => is_block_expr(context, expr, repr), + | ast::ExprKind::Yield(Some(ref expr), YieldKind::Prefix) => { + is_block_expr(context, expr, repr) + } ast::ExprKind::Closure(ref closure) => is_block_expr(context, &closure.body, repr), // This can only be a string lit ast::ExprKind::Lit(_) => { @@ -515,7 +517,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Tup(..) | ast::ExprKind::Use(..) | ast::ExprKind::Type(..) - | ast::ExprKind::Yield(None, _) + | ast::ExprKind::Yield(_, _) | ast::ExprKind::Underscore => false, } } diff --git a/src/tools/rustfmt/tests/source/postfix-yield.rs b/src/tools/rustfmt/tests/source/postfix-yield.rs deleted file mode 100644 index 8a8958f3ad4e8..0000000000000 --- a/src/tools/rustfmt/tests/source/postfix-yield.rs +++ /dev/null @@ -1,15 +0,0 @@ -// This demonstrates a proposed alternate or additional option of having yield in postfix position. -//@ edition: 2024 - -#![feature(gen_blocks, coroutines, coroutine_trait, yield_expr)] - -use std::ops::{Coroutine, CoroutineState}; -use std::pin::pin; - -fn main() { - let mut coro = - pin!(#[coroutine] |_: i32| { let x = 1.yield; - - - (x + 2).yield; }); -} diff --git a/src/tools/rustfmt/tests/target/postfix-yield.rs b/src/tools/rustfmt/tests/target/postfix-yield.rs index 7e94e1e095add..8ee34ec431226 100644 --- a/src/tools/rustfmt/tests/target/postfix-yield.rs +++ b/src/tools/rustfmt/tests/target/postfix-yield.rs @@ -7,6 +7,11 @@ use std::ops::{Coroutine, CoroutineState}; use std::pin::pin; fn main() { - let mut coro = - pin!(#[coroutine] |_: i32| { let x = 1.yield; (x + 2).yield; }); + let mut coro = pin!( + #[coroutine] + |_: i32| { + let x = 1.yield; + (x + 2).await; + } + ); } From 69a3ad0d0a1da2c1e723cbfe4056b629c10d32b1 Mon Sep 17 00:00:00 2001 From: makai410 Date: Tue, 18 Mar 2025 09:48:30 +0800 Subject: [PATCH 10/24] Add `MutMirVisitor` Implement `make_mir_visitor` macro to generate `MirVisitor` and `MutMirVisitor`. Add `ret_local_mut()`, `arg_locals_mut()` and `inner_locals_mut()` to `Body`, specifically for `MutMirVisitor`. --- compiler/stable_mir/src/mir.rs | 2 +- compiler/stable_mir/src/mir/body.rs | 16 + compiler/stable_mir/src/mir/visit.rs | 742 +++++++++++++++------------ 3 files changed, 428 insertions(+), 332 deletions(-) diff --git a/compiler/stable_mir/src/mir.rs b/compiler/stable_mir/src/mir.rs index 82555461d644e..413b5152bb3b3 100644 --- a/compiler/stable_mir/src/mir.rs +++ b/compiler/stable_mir/src/mir.rs @@ -5,4 +5,4 @@ pub mod pretty; pub mod visit; pub use body::*; -pub use visit::MirVisitor; +pub use visit::{MirVisitor, MutMirVisitor}; diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index f8b46f50a5298..b1bf7bce828c3 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -77,6 +77,22 @@ impl Body { &self.locals[self.arg_count + 1..] } + /// Returns a mutable reference to the local that holds this function's return value. + pub(crate) fn ret_local_mut(&mut self) -> &mut LocalDecl { + &mut self.locals[RETURN_LOCAL] + } + + /// Returns a mutable slice of locals corresponding to this function's arguments. + pub(crate) fn arg_locals_mut(&mut self) -> &mut [LocalDecl] { + &mut self.locals[1..][..self.arg_count] + } + + /// Returns a mutable slice of inner locals for this function. + /// Inner locals are those that are neither the return local nor the argument locals. + pub(crate) fn inner_locals_mut(&mut self) -> &mut [LocalDecl] { + &mut self.locals[self.arg_count + 1..] + } + /// Convenience function to get all the locals in this function. /// /// Locals are typically accessed via the more specific methods `ret_local`, diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index d985a98fcbf01..09447e70dfb18 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -39,406 +39,486 @@ use crate::mir::*; use crate::ty::{GenericArgs, MirConst, Region, Ty, TyConst}; use crate::{Error, Opaque, Span}; -pub trait MirVisitor { - fn visit_body(&mut self, body: &Body) { - self.super_body(body) - } - - fn visit_basic_block(&mut self, bb: &BasicBlock) { - self.super_basic_block(bb) - } - - fn visit_ret_decl(&mut self, local: Local, decl: &LocalDecl) { - self.super_ret_decl(local, decl) - } - - fn visit_arg_decl(&mut self, local: Local, decl: &LocalDecl) { - self.super_arg_decl(local, decl) - } - - fn visit_local_decl(&mut self, local: Local, decl: &LocalDecl) { - self.super_local_decl(local, decl) - } - - fn visit_statement(&mut self, stmt: &Statement, location: Location) { - self.super_statement(stmt, location) - } - - fn visit_terminator(&mut self, term: &Terminator, location: Location) { - self.super_terminator(term, location) - } - - fn visit_span(&mut self, span: &Span) { - self.super_span(span) - } +macro_rules! make_mir_visitor { + ($visitor_trait_name:ident, $($mutability:ident)?) => { + pub trait $visitor_trait_name { + fn visit_body(&mut self, body: &$($mutability)? Body) { + self.super_body(body) + } - fn visit_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) { - self.super_place(place, ptx, location) - } + fn visit_basic_block(&mut self, bb: &$($mutability)? BasicBlock) { + self.super_basic_block(bb) + } - fn visit_projection_elem( - &mut self, - place_ref: PlaceRef<'_>, - elem: &ProjectionElem, - ptx: PlaceContext, - location: Location, - ) { - let _ = place_ref; - self.super_projection_elem(elem, ptx, location); - } + fn visit_ret_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { + self.super_ret_decl(local, decl) + } - fn visit_local(&mut self, local: &Local, ptx: PlaceContext, location: Location) { - let _ = (local, ptx, location); - } + fn visit_arg_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { + self.super_arg_decl(local, decl) + } - fn visit_rvalue(&mut self, rvalue: &Rvalue, location: Location) { - self.super_rvalue(rvalue, location) - } + fn visit_local_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { + self.super_local_decl(local, decl) + } - fn visit_operand(&mut self, operand: &Operand, location: Location) { - self.super_operand(operand, location) - } + fn visit_statement(&mut self, stmt: &$($mutability)? Statement, location: Location) { + self.super_statement(stmt, location) + } - fn visit_user_type_projection(&mut self, projection: &UserTypeProjection) { - self.super_user_type_projection(projection) - } + fn visit_terminator(&mut self, term: &$($mutability)? Terminator, location: Location) { + self.super_terminator(term, location) + } - fn visit_ty(&mut self, ty: &Ty, location: Location) { - let _ = location; - self.super_ty(ty) - } + fn visit_span(&mut self, span: &$($mutability)? Span) { + self.super_span(span) + } - fn visit_const_operand(&mut self, constant: &ConstOperand, location: Location) { - self.super_const_operand(constant, location) - } + fn visit_place(&mut self, place: &$($mutability)? Place, ptx: PlaceContext, location: Location) { + self.super_place(place, ptx, location) + } - fn visit_mir_const(&mut self, constant: &MirConst, location: Location) { - self.super_mir_const(constant, location) - } + visit_place_fns!($($mutability)?); - fn visit_ty_const(&mut self, constant: &TyConst, location: Location) { - let _ = location; - self.super_ty_const(constant) - } + fn visit_local(&mut self, local: &$($mutability)? Local, ptx: PlaceContext, location: Location) { + let _ = (local, ptx, location); + } - fn visit_region(&mut self, region: &Region, location: Location) { - let _ = location; - self.super_region(region) - } + fn visit_rvalue(&mut self, rvalue: &$($mutability)? Rvalue, location: Location) { + self.super_rvalue(rvalue, location) + } - fn visit_args(&mut self, args: &GenericArgs, location: Location) { - let _ = location; - self.super_args(args) - } + fn visit_operand(&mut self, operand: &$($mutability)? Operand, location: Location) { + self.super_operand(operand, location) + } - fn visit_assert_msg(&mut self, msg: &AssertMessage, location: Location) { - self.super_assert_msg(msg, location) - } + fn visit_user_type_projection(&mut self, projection: &$($mutability)? UserTypeProjection) { + self.super_user_type_projection(projection) + } - fn visit_var_debug_info(&mut self, var_debug_info: &VarDebugInfo) { - self.super_var_debug_info(var_debug_info); - } + fn visit_ty(&mut self, ty: &$($mutability)? Ty, location: Location) { + let _ = location; + self.super_ty(ty) + } - fn super_body(&mut self, body: &Body) { - let Body { blocks, locals: _, arg_count, var_debug_info, spread_arg: _, span } = body; + fn visit_const_operand(&mut self, constant: &$($mutability)? ConstOperand, location: Location) { + self.super_const_operand(constant, location) + } - for bb in blocks { - self.visit_basic_block(bb); - } + fn visit_mir_const(&mut self, constant: &$($mutability)? MirConst, location: Location) { + self.super_mir_const(constant, location) + } - self.visit_ret_decl(RETURN_LOCAL, body.ret_local()); + fn visit_ty_const(&mut self, constant: &$($mutability)? TyConst, location: Location) { + let _ = location; + self.super_ty_const(constant) + } - for (idx, arg) in body.arg_locals().iter().enumerate() { - self.visit_arg_decl(idx + 1, arg) - } + fn visit_region(&mut self, region: &$($mutability)? Region, location: Location) { + let _ = location; + self.super_region(region) + } - let local_start = arg_count + 1; - for (idx, arg) in body.inner_locals().iter().enumerate() { - self.visit_local_decl(idx + local_start, arg) - } + fn visit_args(&mut self, args: &$($mutability)? GenericArgs, location: Location) { + let _ = location; + self.super_args(args) + } - for info in var_debug_info.iter() { - self.visit_var_debug_info(info); - } + fn visit_assert_msg(&mut self, msg: &$($mutability)? AssertMessage, location: Location) { + self.super_assert_msg(msg, location) + } - self.visit_span(span) - } + fn visit_var_debug_info(&mut self, var_debug_info: &$($mutability)? VarDebugInfo) { + self.super_var_debug_info(var_debug_info); + } - fn super_basic_block(&mut self, bb: &BasicBlock) { - let BasicBlock { statements, terminator } = bb; - for stmt in statements { - self.visit_statement(stmt, Location(stmt.span)); - } - self.visit_terminator(terminator, Location(terminator.span)); - } + fn super_body(&mut self, body: &$($mutability)? Body) { + super_body!(self, body, $($mutability)?); + } - fn super_local_decl(&mut self, local: Local, decl: &LocalDecl) { - let _ = local; - let LocalDecl { ty, span, .. } = decl; - self.visit_ty(ty, Location(*span)); - } + fn super_basic_block(&mut self, bb: &$($mutability)? BasicBlock) { + let BasicBlock { statements, terminator } = bb; + for stmt in statements { + self.visit_statement(stmt, Location(stmt.span)); + } + self.visit_terminator(terminator, Location(terminator.span)); + } - fn super_ret_decl(&mut self, local: Local, decl: &LocalDecl) { - self.super_local_decl(local, decl) - } + fn super_local_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { + let _ = local; + let LocalDecl { ty, span, .. } = decl; + self.visit_ty(ty, Location(*span)); + } - fn super_arg_decl(&mut self, local: Local, decl: &LocalDecl) { - self.super_local_decl(local, decl) - } + fn super_ret_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { + self.super_local_decl(local, decl) + } - fn super_statement(&mut self, stmt: &Statement, location: Location) { - let Statement { kind, span } = stmt; - self.visit_span(span); - match kind { - StatementKind::Assign(place, rvalue) => { - self.visit_place(place, PlaceContext::MUTATING, location); - self.visit_rvalue(rvalue, location); - } - StatementKind::FakeRead(_, place) | StatementKind::PlaceMention(place) => { - self.visit_place(place, PlaceContext::NON_MUTATING, location); - } - StatementKind::SetDiscriminant { place, .. } - | StatementKind::Deinit(place) - | StatementKind::Retag(_, place) => { - self.visit_place(place, PlaceContext::MUTATING, location); - } - StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { - self.visit_local(local, PlaceContext::NON_USE, location); - } - StatementKind::AscribeUserType { place, projections, variance: _ } => { - self.visit_place(place, PlaceContext::NON_USE, location); - self.visit_user_type_projection(projections); - } - StatementKind::Coverage(coverage) => visit_opaque(coverage), - StatementKind::Intrinsic(intrisic) => match intrisic { - NonDivergingIntrinsic::Assume(operand) => { - self.visit_operand(operand, location); - } - NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { - src, - dst, - count, - }) => { - self.visit_operand(src, location); - self.visit_operand(dst, location); - self.visit_operand(count, location); - } - }, - StatementKind::ConstEvalCounter | StatementKind::Nop => {} - } - } + fn super_arg_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) { + self.super_local_decl(local, decl) + } - fn super_terminator(&mut self, term: &Terminator, location: Location) { - let Terminator { kind, span } = term; - self.visit_span(span); - match kind { - TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Abort - | TerminatorKind::Unreachable => {} - TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => { - self.visit_operand(cond, location); - self.visit_assert_msg(msg, location); - } - TerminatorKind::Drop { place, target: _, unwind: _ } => { - self.visit_place(place, PlaceContext::MUTATING, location); - } - TerminatorKind::Call { func, args, destination, target: _, unwind: _ } => { - self.visit_operand(func, location); - for arg in args { - self.visit_operand(arg, location); + fn super_statement(&mut self, stmt: &$($mutability)? Statement, location: Location) { + let Statement { kind, span } = stmt; + self.visit_span(span); + match kind { + StatementKind::Assign(place, rvalue) => { + self.visit_place(place, PlaceContext::MUTATING, location); + self.visit_rvalue(rvalue, location); + } + StatementKind::FakeRead(_, place) | StatementKind::PlaceMention(place) => { + self.visit_place(place, PlaceContext::NON_MUTATING, location); + } + StatementKind::SetDiscriminant { place, .. } + | StatementKind::Deinit(place) + | StatementKind::Retag(_, place) => { + self.visit_place(place, PlaceContext::MUTATING, location); + } + StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => { + self.visit_local(local, PlaceContext::NON_USE, location); + } + StatementKind::AscribeUserType { place, projections, variance: _ } => { + self.visit_place(place, PlaceContext::NON_USE, location); + self.visit_user_type_projection(projections); + } + StatementKind::Coverage(coverage) => visit_opaque(coverage), + StatementKind::Intrinsic(intrisic) => match intrisic { + NonDivergingIntrinsic::Assume(operand) => { + self.visit_operand(operand, location); + } + NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { + src, + dst, + count, + }) => { + self.visit_operand(src, location); + self.visit_operand(dst, location); + self.visit_operand(count, location); + } + }, + StatementKind::ConstEvalCounter | StatementKind::Nop => {} } - self.visit_place(destination, PlaceContext::MUTATING, location); } - TerminatorKind::InlineAsm { operands, .. } => { - for op in operands { - let InlineAsmOperand { in_value, out_place, raw_rpr: _ } = op; - if let Some(input) = in_value { - self.visit_operand(input, location); + + fn super_terminator(&mut self, term: &$($mutability)? Terminator, location: Location) { + let Terminator { kind, span } = term; + self.visit_span(span); + match kind { + TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Unreachable => {} + TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => { + self.visit_operand(cond, location); + self.visit_assert_msg(msg, location); + } + TerminatorKind::Drop { place, target: _, unwind: _ } => { + self.visit_place(place, PlaceContext::MUTATING, location); + } + TerminatorKind::Call { func, args, destination, target: _, unwind: _ } => { + self.visit_operand(func, location); + for arg in args { + self.visit_operand(arg, location); + } + self.visit_place(destination, PlaceContext::MUTATING, location); + } + TerminatorKind::InlineAsm { operands, .. } => { + for op in operands { + let InlineAsmOperand { in_value, out_place, raw_rpr: _ } = op; + if let Some(input) = in_value { + self.visit_operand(input, location); + } + if let Some(output) = out_place { + self.visit_place(output, PlaceContext::MUTATING, location); + } + } } - if let Some(output) = out_place { - self.visit_place(output, PlaceContext::MUTATING, location); + TerminatorKind::Return => { + let $($mutability)? local = RETURN_LOCAL; + self.visit_local(&$($mutability)? local, PlaceContext::NON_MUTATING, location); + } + TerminatorKind::SwitchInt { discr, targets: _ } => { + self.visit_operand(discr, location); } } } - TerminatorKind::Return => { - let local = RETURN_LOCAL; - self.visit_local(&local, PlaceContext::NON_MUTATING, location); - } - TerminatorKind::SwitchInt { discr, targets: _ } => { - self.visit_operand(discr, location); - } - } - } - fn super_span(&mut self, span: &Span) { - let _ = span; - } - - fn super_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) { - let _ = location; - let _ = ptx; - self.visit_local(&place.local, ptx, location); + fn super_span(&mut self, span: &$($mutability)? Span) { + let _ = span; + } - for (idx, elem) in place.projection.iter().enumerate() { - let place_ref = PlaceRef { local: place.local, projection: &place.projection[..idx] }; - self.visit_projection_elem(place_ref, elem, ptx, location); - } - } + fn super_rvalue(&mut self, rvalue: &$($mutability)? Rvalue, location: Location) { + match rvalue { + Rvalue::AddressOf(mutability, place) => { + let pcx = PlaceContext { is_mut: *mutability == RawPtrKind::Mut }; + self.visit_place(place, pcx, location); + } + Rvalue::Aggregate(_, operands) => { + for op in operands { + self.visit_operand(op, location); + } + } + Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { + self.visit_operand(lhs, location); + self.visit_operand(rhs, location); + } + Rvalue::Cast(_, op, ty) => { + self.visit_operand(op, location); + self.visit_ty(ty, location); + } + Rvalue::CopyForDeref(place) | Rvalue::Discriminant(place) | Rvalue::Len(place) => { + self.visit_place(place, PlaceContext::NON_MUTATING, location); + } + Rvalue::Ref(region, kind, place) => { + self.visit_region(region, location); + let pcx = PlaceContext { is_mut: matches!(kind, BorrowKind::Mut { .. }) }; + self.visit_place(place, pcx, location); + } + Rvalue::Repeat(op, constant) => { + self.visit_operand(op, location); + self.visit_ty_const(constant, location); + } + Rvalue::ShallowInitBox(op, ty) => { + self.visit_ty(ty, location); + self.visit_operand(op, location) + } + Rvalue::ThreadLocalRef(_) => {} + Rvalue::NullaryOp(_, ty) => { + self.visit_ty(ty, location); + } + Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => { + self.visit_operand(op, location); + } + } + } - fn super_projection_elem( - &mut self, - elem: &ProjectionElem, - ptx: PlaceContext, - location: Location, - ) { - match elem { - ProjectionElem::Downcast(_idx) => {} - ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } - | ProjectionElem::Deref - | ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {} - ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location), - ProjectionElem::Index(local) => self.visit_local(local, ptx, location), - ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => { - self.visit_ty(ty, location) + fn super_operand(&mut self, operand: &$($mutability)? Operand, location: Location) { + match operand { + Operand::Copy(place) | Operand::Move(place) => { + self.visit_place(place, PlaceContext::NON_MUTATING, location) + } + Operand::Constant(constant) => { + self.visit_const_operand(constant, location); + } + } } - } - } - fn super_rvalue(&mut self, rvalue: &Rvalue, location: Location) { - match rvalue { - Rvalue::AddressOf(mutability, place) => { - let pcx = PlaceContext { is_mut: *mutability == RawPtrKind::Mut }; - self.visit_place(place, pcx, location); + fn super_user_type_projection(&mut self, projection: &$($mutability)? UserTypeProjection) { + // This is a no-op on mir::Visitor. + let _ = projection; } - Rvalue::Aggregate(_, operands) => { - for op in operands { - self.visit_operand(op, location); - } + + fn super_ty(&mut self, ty: &$($mutability)? Ty) { + let _ = ty; } - Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { - self.visit_operand(lhs, location); - self.visit_operand(rhs, location); + + fn super_const_operand(&mut self, constant: &$($mutability)? ConstOperand, location: Location) { + let ConstOperand { span, user_ty: _, const_ } = constant; + self.visit_span(span); + self.visit_mir_const(const_, location); } - Rvalue::Cast(_, op, ty) => { - self.visit_operand(op, location); + + fn super_mir_const(&mut self, constant: &$($mutability)? MirConst, location: Location) { + let MirConst { kind: _, ty, id: _ } = constant; self.visit_ty(ty, location); } - Rvalue::CopyForDeref(place) | Rvalue::Discriminant(place) | Rvalue::Len(place) => { - self.visit_place(place, PlaceContext::NON_MUTATING, location); - } - Rvalue::Ref(region, kind, place) => { - self.visit_region(region, location); - let pcx = PlaceContext { is_mut: matches!(kind, BorrowKind::Mut { .. }) }; - self.visit_place(place, pcx, location); + + fn super_ty_const(&mut self, constant: &$($mutability)? TyConst) { + let _ = constant; } - Rvalue::Repeat(op, constant) => { - self.visit_operand(op, location); - self.visit_ty_const(constant, location); + + fn super_region(&mut self, region: &$($mutability)? Region) { + let _ = region; } - Rvalue::ShallowInitBox(op, ty) => { - self.visit_ty(ty, location); - self.visit_operand(op, location) + + fn super_args(&mut self, args: &$($mutability)? GenericArgs) { + let _ = args; } - Rvalue::ThreadLocalRef(_) => {} - Rvalue::NullaryOp(_, ty) => { - self.visit_ty(ty, location); + + fn super_var_debug_info(&mut self, var_debug_info: &$($mutability)? VarDebugInfo) { + let VarDebugInfo { source_info, composite, value, name: _, argument_index: _ } = + var_debug_info; + self.visit_span(&$($mutability)? source_info.span); + let location = Location(source_info.span); + if let Some(composite) = composite { + self.visit_ty(&$($mutability)? composite.ty, location); + } + match value { + VarDebugInfoContents::Place(place) => { + self.visit_place(place, PlaceContext::NON_USE, location); + } + VarDebugInfoContents::Const(constant) => { + self.visit_mir_const(&$($mutability)? constant.const_, location); + } + } } - Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => { - self.visit_operand(op, location); + + fn super_assert_msg(&mut self, msg: &$($mutability)? AssertMessage, location: Location) { + match msg { + AssertMessage::BoundsCheck { len, index } => { + self.visit_operand(len, location); + self.visit_operand(index, location); + } + AssertMessage::Overflow(_, left, right) => { + self.visit_operand(left, location); + self.visit_operand(right, location); + } + AssertMessage::OverflowNeg(op) + | AssertMessage::DivisionByZero(op) + | AssertMessage::RemainderByZero(op) => { + self.visit_operand(op, location); + } + AssertMessage::ResumedAfterReturn(_) + | AssertMessage::ResumedAfterPanic(_) + | AssertMessage::NullPointerDereference => { + //nothing to visit + } + AssertMessage::MisalignedPointerDereference { required, found } => { + self.visit_operand(required, location); + self.visit_operand(found, location); + } + } } } - } + }; +} - fn super_operand(&mut self, operand: &Operand, location: Location) { - match operand { - Operand::Copy(place) | Operand::Move(place) => { - self.visit_place(place, PlaceContext::NON_MUTATING, location) - } - Operand::Constant(constant) => { - self.visit_const_operand(constant, location); - } +macro_rules! super_body { + ($self:ident, $body:ident, mut) => { + for bb in $body.blocks.iter_mut() { + $self.visit_basic_block(bb); } - } - fn super_user_type_projection(&mut self, projection: &UserTypeProjection) { - // This is a no-op on mir::Visitor. - let _ = projection; - } + $self.visit_ret_decl(RETURN_LOCAL, $body.ret_local_mut()); - fn super_ty(&mut self, ty: &Ty) { - let _ = ty; - } + for (idx, arg) in $body.arg_locals_mut().iter_mut().enumerate() { + $self.visit_arg_decl(idx + 1, arg) + } - fn super_const_operand(&mut self, constant: &ConstOperand, location: Location) { - let ConstOperand { span, user_ty: _, const_ } = constant; - self.visit_span(span); - self.visit_mir_const(const_, location); - } + let local_start = $body.arg_count + 1; + for (idx, arg) in $body.inner_locals_mut().iter_mut().enumerate() { + $self.visit_local_decl(idx + local_start, arg) + } - fn super_mir_const(&mut self, constant: &MirConst, location: Location) { - let MirConst { kind: _, ty, id: _ } = constant; - self.visit_ty(ty, location); - } + for info in $body.var_debug_info.iter_mut() { + $self.visit_var_debug_info(info); + } - fn super_ty_const(&mut self, constant: &TyConst) { - let _ = constant; - } + $self.visit_span(&mut $body.span) + }; - fn super_region(&mut self, region: &Region) { - let _ = region; - } + ($self:ident, $body:ident, ) => { + let Body { blocks, locals: _, arg_count, var_debug_info, spread_arg: _, span } = $body; - fn super_args(&mut self, args: &GenericArgs) { - let _ = args; - } + for bb in blocks { + $self.visit_basic_block(bb); + } - fn super_var_debug_info(&mut self, var_debug_info: &VarDebugInfo) { - let VarDebugInfo { source_info, composite, value, name: _, argument_index: _ } = - var_debug_info; - self.visit_span(&source_info.span); - let location = Location(source_info.span); - if let Some(composite) = composite { - self.visit_ty(&composite.ty, location); + $self.visit_ret_decl(RETURN_LOCAL, $body.ret_local()); + + for (idx, arg) in $body.arg_locals().iter().enumerate() { + $self.visit_arg_decl(idx + 1, arg) } - match value { - VarDebugInfoContents::Place(place) => { - self.visit_place(place, PlaceContext::NON_USE, location); - } - VarDebugInfoContents::Const(constant) => { - self.visit_mir_const(&constant.const_, location); - } + + let local_start = arg_count + 1; + for (idx, arg) in $body.inner_locals().iter().enumerate() { + $self.visit_local_decl(idx + local_start, arg) } - } - fn super_assert_msg(&mut self, msg: &AssertMessage, location: Location) { - match msg { - AssertMessage::BoundsCheck { len, index } => { - self.visit_operand(len, location); - self.visit_operand(index, location); - } - AssertMessage::Overflow(_, left, right) => { - self.visit_operand(left, location); - self.visit_operand(right, location); + for info in var_debug_info.iter() { + $self.visit_var_debug_info(info); + } + + $self.visit_span(span) + }; +} + +macro_rules! visit_place_fns { + (mut) => { + fn super_place(&mut self, place: &mut Place, ptx: PlaceContext, location: Location) { + self.visit_local(&mut place.local, ptx, location); + + for elem in place.projection.iter_mut() { + self.visit_projection_elem(elem, ptx, location); } - AssertMessage::OverflowNeg(op) - | AssertMessage::DivisionByZero(op) - | AssertMessage::RemainderByZero(op) => { - self.visit_operand(op, location); + } + + // We don't have to replicate the `process_projection()` like we did in + // `rustc_middle::mir::visit.rs` here because the `projection` field in `Place` + // of Stable-MIR is not an immutable borrow, unlike in `Place` of MIR. + fn visit_projection_elem( + &mut self, + elem: &mut ProjectionElem, + ptx: PlaceContext, + location: Location, + ) { + self.super_projection_elem(elem, ptx, location) + } + + fn super_projection_elem( + &mut self, + elem: &mut ProjectionElem, + ptx: PlaceContext, + location: Location, + ) { + match elem { + ProjectionElem::Deref => {} + ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location), + ProjectionElem::Index(local) => self.visit_local(local, ptx, location), + ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } => {} + ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {} + ProjectionElem::Downcast(_idx) => {} + ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location), + ProjectionElem::Subtype(ty) => self.visit_ty(ty, location), } - AssertMessage::ResumedAfterReturn(_) - | AssertMessage::ResumedAfterPanic(_) - | AssertMessage::NullPointerDereference => { - //nothing to visit + } + }; + + () => { + fn super_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) { + self.visit_local(&place.local, ptx, location); + + for (idx, elem) in place.projection.iter().enumerate() { + let place_ref = + PlaceRef { local: place.local, projection: &place.projection[..idx] }; + self.visit_projection_elem(place_ref, elem, ptx, location); } - AssertMessage::MisalignedPointerDereference { required, found } => { - self.visit_operand(required, location); - self.visit_operand(found, location); + } + + fn visit_projection_elem<'a>( + &mut self, + place_ref: PlaceRef<'a>, + elem: &ProjectionElem, + ptx: PlaceContext, + location: Location, + ) { + let _ = place_ref; + self.super_projection_elem(elem, ptx, location); + } + + fn super_projection_elem( + &mut self, + elem: &ProjectionElem, + ptx: PlaceContext, + location: Location, + ) { + match elem { + ProjectionElem::Deref => {} + ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location), + ProjectionElem::Index(local) => self.visit_local(local, ptx, location), + ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } => {} + ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {} + ProjectionElem::Downcast(_idx) => {} + ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location), + ProjectionElem::Subtype(ty) => self.visit_ty(ty, location), } } - } + }; } +make_mir_visitor!(MirVisitor,); +make_mir_visitor!(MutMirVisitor, mut); + /// This function is a no-op that gets used to ensure this visitor is kept up-to-date. /// /// The idea is that whenever we replace an Opaque type by a real type, the compiler will fail From ad315f6074868024689aaa98021bffdd590e0841 Mon Sep 17 00:00:00 2001 From: makai410 Date: Tue, 18 Mar 2025 09:49:06 +0800 Subject: [PATCH 11/24] Add test for `MutMirVisitor` --- tests/ui-fulldeps/stable-mir/smir_visitor.rs | 81 +++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/tests/ui-fulldeps/stable-mir/smir_visitor.rs b/tests/ui-fulldeps/stable-mir/smir_visitor.rs index cffb41742b4e4..0a579a07cef16 100644 --- a/tests/ui-fulldeps/stable-mir/smir_visitor.rs +++ b/tests/ui-fulldeps/stable-mir/smir_visitor.rs @@ -18,6 +18,7 @@ extern crate stable_mir; use rustc_smir::rustc_internal; use stable_mir::mir::MirVisitor; +use stable_mir::mir::MutMirVisitor; use stable_mir::*; use std::collections::HashSet; use std::io::Write; @@ -99,6 +100,83 @@ impl<'a> mir::MirVisitor for TestVisitor<'a> { } } +fn test_mut_visitor() -> ControlFlow<()> { + let main_fn = stable_mir::entry_fn(); + let mut main_body = main_fn.unwrap().expect_body(); + let locals = main_body.locals().to_vec(); + let mut main_visitor = TestMutVisitor::collect(locals); + main_visitor.visit_body(&mut main_body); + assert!(main_visitor.ret_val.is_some()); + assert!(main_visitor.args.is_empty()); + assert!(main_visitor.tys.contains(&main_visitor.ret_val.unwrap().ty)); + assert!(!main_visitor.calls.is_empty()); + + let exit_fn = main_visitor.calls.last().unwrap(); + assert!(exit_fn.mangled_name().contains("exit_fn"), "Unexpected last function: {exit_fn:?}"); + + let mut exit_body = exit_fn.body().unwrap(); + let locals = exit_body.locals().to_vec(); + let mut exit_visitor = TestMutVisitor::collect(locals); + exit_visitor.visit_body(&mut exit_body); + assert!(exit_visitor.ret_val.is_some()); + assert_eq!(exit_visitor.args.len(), 1); + assert!(exit_visitor.tys.contains(&exit_visitor.ret_val.unwrap().ty)); + assert!(exit_visitor.tys.contains(&exit_visitor.args[0].ty)); + ControlFlow::Continue(()) +} + +struct TestMutVisitor { + locals: Vec, + pub tys: HashSet, + pub ret_val: Option, + pub args: Vec, + pub calls: Vec, +} + +impl TestMutVisitor { + fn collect(locals: Vec) -> TestMutVisitor { + let visitor = TestMutVisitor { + locals: locals, + tys: Default::default(), + ret_val: None, + args: vec![], + calls: vec![], + }; + visitor + } +} + +impl mir::MutMirVisitor for TestMutVisitor { + fn visit_ty(&mut self, ty: &mut ty::Ty, _location: mir::visit::Location) { + self.tys.insert(*ty); + self.super_ty(ty) + } + + fn visit_ret_decl(&mut self, local: mir::Local, decl: &mut mir::LocalDecl) { + assert!(local == mir::RETURN_LOCAL); + assert!(self.ret_val.is_none()); + self.ret_val = Some(decl.clone()); + self.super_ret_decl(local, decl); + } + + fn visit_arg_decl(&mut self, local: mir::Local, decl: &mut mir::LocalDecl) { + self.args.push(decl.clone()); + assert_eq!(local, self.args.len()); + self.super_arg_decl(local, decl); + } + + fn visit_terminator(&mut self, term: &mut mir::Terminator, location: mir::visit::Location) { + if let mir::TerminatorKind::Call { func, .. } = &mut term.kind { + let ty::TyKind::RigidTy(ty) = func.ty(&self.locals).unwrap().kind() else { + unreachable!() + }; + let ty::RigidTy::FnDef(def, args) = ty else { unreachable!() }; + self.calls.push(mir::mono::Instance::resolve(def, &args).unwrap()); + } + self.super_terminator(term, location); + } +} + /// This test will generate and analyze a dummy crate using the stable mir. /// For that, it will first write the dummy crate into a file. /// Then it will create a `StableMir` using custom arguments and then @@ -113,7 +191,8 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, test_visitor).unwrap(); + run!(args.clone(), test_visitor).unwrap(); + run!(args, test_mut_visitor).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { From a0c3dd4df4f3e30331ddbd3b2507f3f8b18d4a3c Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Sat, 1 Mar 2025 12:34:09 -0800 Subject: [PATCH 12/24] Optimize io::Write::write_fmt for constant strings When the formatting args to `fmt::Write::write_fmt` are a statically known string, it simplifies to only calling `write_str` without a runtime branch. Do the same in `io::Write::write_fmt` with `write_all`. Also, match the convention of `fmt::Write` for the name of `args`. --- library/core/src/fmt/mod.rs | 3 +- library/std/src/io/mod.rs | 81 +++++++++++++++++++++---------------- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index b13c7ee5aa28b..48f3604447166 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -710,9 +710,10 @@ impl<'a> Arguments<'a> { } /// Same as [`Arguments::as_str`], but will only return `Some(s)` if it can be determined at compile time. + #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] #[must_use] #[inline] - fn as_statically_known_str(&self) -> Option<&'static str> { + pub fn as_statically_known_str(&self) -> Option<&'static str> { let s = self.as_str(); if core::intrinsics::is_val_statically_known(s.is_some()) { s } else { None } } diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 679549093b398..ad38201a0c458 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -612,6 +612,47 @@ pub(crate) fn default_read_buf_exact( Ok(()) } +pub(crate) fn default_write_fmt( + this: &mut W, + args: fmt::Arguments<'_>, +) -> Result<()> { + // Create a shim which translates a `Write` to a `fmt::Write` and saves off + // I/O errors, instead of discarding them. + struct Adapter<'a, T: ?Sized + 'a> { + inner: &'a mut T, + error: Result<()>, + } + + impl fmt::Write for Adapter<'_, T> { + fn write_str(&mut self, s: &str) -> fmt::Result { + match self.inner.write_all(s.as_bytes()) { + Ok(()) => Ok(()), + Err(e) => { + self.error = Err(e); + Err(fmt::Error) + } + } + } + } + + let mut output = Adapter { inner: this, error: Ok(()) }; + match fmt::write(&mut output, args) { + Ok(()) => Ok(()), + Err(..) => { + // Check whether the error came from the underlying `Write`. + if output.error.is_err() { + output.error + } else { + // This shouldn't happen: the underlying stream did not error, + // but somehow the formatter still errored? + panic!( + "a formatting trait implementation returned an error when the underlying stream did not" + ); + } + } + } +} + /// The `Read` trait allows for reading bytes from a source. /// /// Implementors of the `Read` trait are called 'readers'. @@ -1866,41 +1907,11 @@ pub trait Write { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<()> { - // Create a shim which translates a Write to a fmt::Write and saves - // off I/O errors. instead of discarding them - struct Adapter<'a, T: ?Sized + 'a> { - inner: &'a mut T, - error: Result<()>, - } - - impl fmt::Write for Adapter<'_, T> { - fn write_str(&mut self, s: &str) -> fmt::Result { - match self.inner.write_all(s.as_bytes()) { - Ok(()) => Ok(()), - Err(e) => { - self.error = Err(e); - Err(fmt::Error) - } - } - } - } - - let mut output = Adapter { inner: self, error: Ok(()) }; - match fmt::write(&mut output, fmt) { - Ok(()) => Ok(()), - Err(..) => { - // check if the error came from the underlying `Write` or not - if output.error.is_err() { - output.error - } else { - // This shouldn't happen: the underlying stream did not error, but somehow - // the formatter still errored? - panic!( - "a formatting trait implementation returned an error when the underlying stream did not" - ); - } - } + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<()> { + if let Some(s) = args.as_statically_known_str() { + self.write_all(s.as_bytes()) + } else { + default_write_fmt(self, args) } } From 5fe1e47f80de2c5edd63d575ad311ccbd55d8f46 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 18 Mar 2025 09:59:00 +0100 Subject: [PATCH 13/24] reintroduce remote-test support in run-make tests The old Makefile-based infrastructure included support for executing binaries with remote-test-client if configured, but that didn't get ported to run_make_support as part of the rmake migration. This PR re-introduces back that support, with the same implementation (and limitations) of the original Makefile-based support. --- src/tools/run-make-support/src/run.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs index 7812863ccc2c8..60e711d340278 100644 --- a/src/tools/run-make-support/src/run.rs +++ b/src/tools/run-make-support/src/run.rs @@ -12,7 +12,20 @@ fn run_common(name: &str, args: Option<&[&str]>) -> Command { bin_path.push(cwd()); bin_path.push(name); let ld_lib_path_envvar = env_var("LD_LIB_PATH_ENVVAR"); - let mut cmd = Command::new(bin_path); + + let mut cmd = if let Some(rtc) = env::var_os("REMOTE_TEST_CLIENT") { + let mut cmd = Command::new(rtc); + cmd.arg("run"); + // FIXME: the "0" indicates how many support files should be uploaded along with the binary + // to execute. If a test requires additional files to be pushed to the remote machine, this + // will have to be changed (and the support files will have to be uploaded). + cmd.arg("0"); + cmd.arg(bin_path); + cmd + } else { + Command::new(bin_path) + }; + if let Some(args) = args { for arg in args { cmd.arg(arg); From a3669b89825e6f1aabaa3e3993c1a9f9d7b70306 Mon Sep 17 00:00:00 2001 From: "aaishwarymishra@gmail.com" Date: Wed, 12 Mar 2025 16:54:14 +0530 Subject: [PATCH 14/24] updated compiler tests for rustc_intrinsic' Update compiler/rustc_error_codes/src/error_codes/E0622.md Co-authored-by: Ralf Jung reverted chages on E0622.md updated E0622.md --- compiler/rustc_error_codes/src/error_codes/E0092.md | 12 +++++------- compiler/rustc_error_codes/src/error_codes/E0093.md | 10 ++++------ compiler/rustc_error_codes/src/error_codes/E0211.md | 10 ++++------ compiler/rustc_error_codes/src/error_codes/E0511.md | 10 ++++------ 4 files changed, 17 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0092.md b/compiler/rustc_error_codes/src/error_codes/E0092.md index 84ec0656d1ac1..be459d040c28d 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0092.md +++ b/compiler/rustc_error_codes/src/error_codes/E0092.md @@ -6,10 +6,9 @@ Erroneous code example: #![feature(intrinsics)] #![allow(internal_features)] -extern "rust-intrinsic" { - fn atomic_foo(); // error: unrecognized atomic operation - // function -} +#[rustc_intrinsic] +unsafe fn atomic_foo(); // error: unrecognized atomic operation + // function ``` Please check you didn't make a mistake in the function's name. All intrinsic @@ -20,7 +19,6 @@ functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in #![feature(intrinsics)] #![allow(internal_features)] -extern "rust-intrinsic" { - fn atomic_fence_seqcst(); // ok! -} +#[rustc_intrinsic] +unsafe fn atomic_fence_seqcst(); // ok! ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0093.md b/compiler/rustc_error_codes/src/error_codes/E0093.md index 2bda4d74f726d..9929a0699273d 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0093.md +++ b/compiler/rustc_error_codes/src/error_codes/E0093.md @@ -6,9 +6,8 @@ Erroneous code example: #![feature(intrinsics)] #![allow(internal_features)] -extern "rust-intrinsic" { - fn foo(); // error: unrecognized intrinsic function: `foo` -} +#[rustc_intrinsic] +unsafe fn foo(); // error: unrecognized intrinsic function: `foo` fn main() { unsafe { @@ -25,9 +24,8 @@ functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in #![feature(intrinsics)] #![allow(internal_features)] -extern "rust-intrinsic" { - fn atomic_fence_seqcst(); // ok! -} +#[rustc_intrinsic] +unsafe fn atomic_fence_seqcst(); // ok! fn main() { unsafe { diff --git a/compiler/rustc_error_codes/src/error_codes/E0211.md b/compiler/rustc_error_codes/src/error_codes/E0211.md index 7aa42628549f8..c702f14d4d6d4 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0211.md +++ b/compiler/rustc_error_codes/src/error_codes/E0211.md @@ -7,9 +7,8 @@ used. Erroneous code examples: #![feature(intrinsics)] #![allow(internal_features)] -extern "rust-intrinsic" { - fn unreachable(); // error: intrinsic has wrong type -} +#[rustc_intrinsic] +unsafe fn unreachable(); // error: intrinsic has wrong type // or: @@ -43,9 +42,8 @@ For the first code example, please check the function definition. Example: #![feature(intrinsics)] #![allow(internal_features)] -extern "rust-intrinsic" { - fn unreachable() -> !; // ok! -} +#[rustc_intrinsic] +unsafe fn unreachable() -> !; // ok! ``` The second case example is a bit particular: the main function must always diff --git a/compiler/rustc_error_codes/src/error_codes/E0511.md b/compiler/rustc_error_codes/src/error_codes/E0511.md index 45ff49bdebb29..0fb1cfda67dc6 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0511.md +++ b/compiler/rustc_error_codes/src/error_codes/E0511.md @@ -5,9 +5,8 @@ Erroneous code example: ```compile_fail,E0511 #![feature(intrinsics)] -extern "rust-intrinsic" { - fn simd_add(a: T, b: T) -> T; -} +#[rustc_intrinsic] +unsafe fn simd_add(a: T, b: T) -> T; fn main() { unsafe { simd_add(0, 1); } @@ -25,9 +24,8 @@ The generic type has to be a SIMD type. Example: #[derive(Copy, Clone)] struct i32x2([i32; 2]); -extern "rust-intrinsic" { - fn simd_add(a: T, b: T) -> T; -} +#[rustc_intrinsic] +unsafe fn simd_add(a: T, b: T) -> T; unsafe { simd_add(i32x2([0, 0]), i32x2([1, 2])); } // ok! ``` From 299e5d05147c3d3deefd3f85f6e994b5d05fb2f8 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 18 Mar 2025 10:50:33 -0700 Subject: [PATCH 15/24] Apply suggestions from code review Co-authored-by: Travis Cross --- compiler/rustc_ast_pretty/src/pprust/state/expr.rs | 2 +- compiler/rustc_parse/src/parser/expr.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 9e53ed41c46c4..caba5f2721ab1 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -774,7 +774,7 @@ impl<'a> State<'a> { } } ast::ExprKind::Yield(e, YieldKind::Postfix) => { - // it's not possible to have a postfix yield with no expression. + // It's not possible to have a postfix yield with no expression. let e = e.as_ref().unwrap(); self.print_expr_cond_paren( e, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 28d100074f3eb..15a625314b4a9 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1311,7 +1311,7 @@ impl<'a> Parser<'a> { return self.parse_match_block(lo, match_span, self_arg, MatchKind::Postfix); } - // Post-fix yield + // Parse a postfix `yield`. if self.eat_keyword(exp!(Yield)) { let yield_span = self.prev_token.span; self.psess.gated_spans.gate(sym::yield_expr, yield_span); From 2bd7f73c2175c1f0ad56a0be4b5c39e2fc5ab97b Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 18 Mar 2025 12:19:43 -0700 Subject: [PATCH 16/24] Refactor YieldKind so postfix yield must have an expression --- compiler/rustc_ast/src/ast.rs | 37 +++++++++++++++++-- compiler/rustc_ast/src/mut_visit.rs | 7 +++- compiler/rustc_ast/src/util/classify.rs | 10 +++-- compiler/rustc_ast/src/visit.rs | 4 +- compiler/rustc_ast_lowering/src/expr.rs | 2 +- compiler/rustc_ast_lowering/src/format.rs | 2 +- .../rustc_ast_pretty/src/pprust/state/expr.rs | 6 +-- .../src/assert/context.rs | 2 +- compiler/rustc_parse/src/parser/expr.rs | 9 +++-- .../src/suspicious_operation_groupings.rs | 2 +- .../clippy/clippy_utils/src/ast_utils/mod.rs | 2 +- src/tools/rustfmt/src/chains.rs | 4 +- src/tools/rustfmt/src/expr.rs | 4 +- src/tools/rustfmt/src/utils.rs | 4 +- 14 files changed, 65 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 9dcdd86834372..5b7545b339663 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1657,7 +1657,7 @@ pub enum ExprKind { Try(P), /// A `yield`, with an optional value to be yielded. - Yield(Option>, YieldKind), + Yield(YieldKind), /// A `do yeet` (aka `throw`/`fail`/`bail`/`raise`/whatever), /// with an optional value to be returned. @@ -1904,12 +1904,41 @@ pub enum MatchKind { } /// The kind of yield expression -#[derive(Clone, Copy, Encodable, Decodable, Debug, PartialEq)] +#[derive(Clone, Encodable, Decodable, Debug)] pub enum YieldKind { /// yield expr { ... } - Prefix, + Prefix(Option>), /// expr.yield { ... } - Postfix, + Postfix(P), +} + +impl YieldKind { + /// Returns the expression inside the yield expression, if any. + /// + /// For postfix yields, this is guaranteed to be `Some`. + pub const fn expr(&self) -> Option<&P> { + match self { + YieldKind::Prefix(expr) => expr.as_ref(), + YieldKind::Postfix(expr) => Some(expr), + } + } + + /// Returns a mutable reference to the expression being yielded, if any. + pub const fn expr_mut(&mut self) -> Option<&mut P> { + match self { + YieldKind::Prefix(expr) => expr.as_mut(), + YieldKind::Postfix(expr) => Some(expr), + } + } + + /// Returns true if both yields are prefix or both are postfix. + pub const fn same_kind(&self, other: &Self) -> bool { + match (self, other) { + (YieldKind::Prefix(_), YieldKind::Prefix(_)) => true, + (YieldKind::Postfix(_), YieldKind::Postfix(_)) => true, + _ => false, + } + } } /// A literal in a meta item. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 5a9df6ffadf03..b159e136245da 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1813,8 +1813,11 @@ pub fn walk_expr(vis: &mut T, Expr { kind, id, span, attrs, token ExprKind::Paren(expr) => { vis.visit_expr(expr); } - ExprKind::Yield(expr, _) => { - visit_opt(expr, |expr| vis.visit_expr(expr)); + ExprKind::Yield(kind) => { + let expr = kind.expr_mut(); + if let Some(expr) = expr { + vis.visit_expr(expr); + } } ExprKind::Try(expr) => vis.visit_expr(expr), ExprKind::TryBlock(body) => vis.visit_block(body), diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 116847af9f497..989ebe14bf8fc 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -182,11 +182,14 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option> { | Range(_, Some(e), _) | Ret(Some(e)) | Unary(_, e) - | Yield(Some(e), _) | Yeet(Some(e)) | Become(e) => { expr = e; } + Yield(kind) => match kind.expr() { + Some(e) => expr = e, + None => break None, + }, Closure(closure) => { expr = &closure.body; } @@ -217,7 +220,6 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option> { Break(_, None) | Range(_, None, _) | Ret(None) - | Yield(None, _) | Array(_) | Call(_, _) | MethodCall(_) @@ -237,7 +239,9 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option> { | Yeet(None) | UnsafeBinderCast(..) | Err(_) - | Dummy => break None, + | Dummy => { + break None; + } } } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index a72e834e17a2f..ce8d6df75afb2 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1269,8 +1269,8 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V try_visit!(visitor.visit_ty(container)); walk_list!(visitor, visit_ident, fields.iter()); } - ExprKind::Yield(optional_expression, _) => { - visit_opt!(visitor, visit_expr, optional_expression); + ExprKind::Yield(kind) => { + visit_opt!(visitor, visit_expr, kind.expr()); } ExprKind::Try(subexpression) => try_visit!(visitor.visit_expr(subexpression)), ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)), diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 19a08f92ce75c..7f3d060bb8a37 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -351,7 +351,7 @@ impl<'hir> LoweringContext<'_, 'hir> { rest, ) } - ExprKind::Yield(opt_expr, _) => self.lower_expr_yield(e.span, opt_expr.as_deref()), + ExprKind::Yield(kind) => self.lower_expr_yield(e.span, kind.expr().map(|x| &**x)), ExprKind::Err(guar) => hir::ExprKind::Err(*guar), ExprKind::UnsafeBinderCast(kind, expr, ty) => hir::ExprKind::UnsafeBinderCast( diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 2bbf957feebe8..faa47274f96ce 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -642,7 +642,7 @@ fn may_contain_yield_point(e: &ast::Expr) -> bool { type Result = ControlFlow<()>; fn visit_expr(&mut self, e: &ast::Expr) -> ControlFlow<()> { - if let ast::ExprKind::Await(_, _) | ast::ExprKind::Yield(_, _) = e.kind { + if let ast::ExprKind::Await(_, _) | ast::ExprKind::Yield(_) = e.kind { ControlFlow::Break(()) } else { visit::walk_expr(self, e) diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index caba5f2721ab1..7d9dc89bd7567 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -761,7 +761,7 @@ impl<'a> State<'a> { self.print_expr(e, FixupContext::default()); self.pclose(); } - ast::ExprKind::Yield(e, YieldKind::Prefix) => { + ast::ExprKind::Yield(YieldKind::Prefix(e)) => { self.word("yield"); if let Some(expr) = e { @@ -773,9 +773,7 @@ impl<'a> State<'a> { ); } } - ast::ExprKind::Yield(e, YieldKind::Postfix) => { - // It's not possible to have a postfix yield with no expression. - let e = e.as_ref().unwrap(); + ast::ExprKind::Yield(YieldKind::Postfix(e)) => { self.print_expr_cond_paren( e, e.precedence() < ExprPrecedence::Unambiguous, diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 54c3cebedfc0e..a949ab94f3ad7 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -323,7 +323,7 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::While(_, _, _) | ExprKind::Yeet(_) | ExprKind::Become(_) - | ExprKind::Yield(_, _) + | ExprKind::Yield(_) | ExprKind::UnsafeBinderCast(..) => {} } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 15a625314b4a9..fc9a511d56a55 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1315,8 +1315,9 @@ impl<'a> Parser<'a> { if self.eat_keyword(exp!(Yield)) { let yield_span = self.prev_token.span; self.psess.gated_spans.gate(sym::yield_expr, yield_span); - return Ok(self - .mk_expr(lo.to(yield_span), ExprKind::Yield(Some(self_arg), YieldKind::Postfix))); + return Ok( + self.mk_expr(lo.to(yield_span), ExprKind::Yield(YieldKind::Postfix(self_arg))) + ); } let fn_span_lo = self.token.span; @@ -1893,7 +1894,7 @@ impl<'a> Parser<'a> { /// Parse `"yield" expr?`. fn parse_expr_yield(&mut self) -> PResult<'a, P> { let lo = self.prev_token.span; - let kind = ExprKind::Yield(self.parse_expr_opt()?, YieldKind::Prefix); + let kind = ExprKind::Yield(YieldKind::Prefix(self.parse_expr_opt()?)); let span = lo.to(self.prev_token.span); self.psess.gated_spans.gate(sym::yield_expr, span); let expr = self.mk_expr(span, kind); @@ -4047,7 +4048,7 @@ impl MutVisitor for CondChecker<'_> { | ExprKind::MacCall(_) | ExprKind::Struct(_) | ExprKind::Repeat(_, _) - | ExprKind::Yield(_, _) + | ExprKind::Yield(_) | ExprKind::Yeet(_) | ExprKind::Become(_) | ExprKind::IncludedBytes(_) diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs index 206912d8de40d..0d809c17989de 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs @@ -528,7 +528,7 @@ fn ident_difference_expr_with_base_location( &strip_non_ident_wrappers(left).kind, &strip_non_ident_wrappers(right).kind, ) { - (Yield(_, _), Yield(_, _)) + (Yield(_), Yield(_)) | (Try(_), Try(_)) | (Paren(_), Paren(_)) | (Repeat(_, _), Repeat(_, _)) diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index deda6030831ec..54261079fcad8 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -201,7 +201,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lt, rt), (Block(lb, ll), Block(rb, rl)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lb, rb), (TryBlock(l), TryBlock(r)) => eq_block(l, r), - (Yield(l, lk), Yield(r, rk)) => eq_expr_opt(l.as_ref(), r.as_ref()) && lk == rk, + (Yield(l), Yield(r)) => eq_expr_opt(l.expr(), r.expr()) && l.same_kind(r), (Ret(l), Ret(r)) => eq_expr_opt(l.as_ref(), r.as_ref()), (Break(ll, le), Break(rl, re)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_expr_opt(le.as_ref(), re.as_ref()), (Continue(ll), Continue(rl)) => eq_label(ll.as_ref(), rl.as_ref()), diff --git a/src/tools/rustfmt/src/chains.rs b/src/tools/rustfmt/src/chains.rs index fabb44005532d..034ecde068a98 100644 --- a/src/tools/rustfmt/src/chains.rs +++ b/src/tools/rustfmt/src/chains.rs @@ -259,7 +259,7 @@ impl ChainItemKind { let span = mk_sp(nested.span.hi(), expr.span.hi()); (ChainItemKind::Await, span) } - ast::ExprKind::Yield(Some(ref nested), ast::YieldKind::Postfix) => { + ast::ExprKind::Yield(ast::YieldKind::Postfix(ref nested)) => { let span = mk_sp(nested.span.hi(), expr.span.hi()); (ChainItemKind::Yield, span) } @@ -516,7 +516,7 @@ impl Chain { ast::ExprKind::Field(ref subexpr, _) | ast::ExprKind::Try(ref subexpr) | ast::ExprKind::Await(ref subexpr, _) - | ast::ExprKind::Yield(Some(ref subexpr), ast::YieldKind::Postfix) => Some(SubExpr { + | ast::ExprKind::Yield(ast::YieldKind::Postfix(ref subexpr)) => Some(SubExpr { expr: Self::convert_try(subexpr, context), is_method_call_receiver: false, }), diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 92c1ffa6076d3..e866f13efc73e 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -221,7 +221,7 @@ pub(crate) fn format_expr( Ok(format!("break{id_str}")) } } - ast::ExprKind::Yield(ref opt_expr, ast::YieldKind::Prefix) => { + ast::ExprKind::Yield(ast::YieldKind::Prefix(ref opt_expr)) => { if let Some(ref expr) = *opt_expr { rewrite_unary_prefix(context, "yield ", &**expr, shape) } else { @@ -244,7 +244,7 @@ pub(crate) fn format_expr( | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) | ast::ExprKind::Await(_, _) - | ast::ExprKind::Yield(_, ast::YieldKind::Postfix) => rewrite_chain(expr, context, shape), + | ast::ExprKind::Yield(ast::YieldKind::Postfix(_)) => rewrite_chain(expr, context, shape), ast::ExprKind::MacCall(ref mac) => { rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|_| { wrap_str( diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index 1811752c3c439..fcd475b1784f5 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -485,7 +485,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Index(_, ref expr, _) | ast::ExprKind::Unary(_, ref expr) | ast::ExprKind::Try(ref expr) - | ast::ExprKind::Yield(Some(ref expr), YieldKind::Prefix) => { + | ast::ExprKind::Yield(YieldKind::Prefix(Some(ref expr))) => { is_block_expr(context, expr, repr) } ast::ExprKind::Closure(ref closure) => is_block_expr(context, &closure.body, repr), @@ -517,7 +517,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Tup(..) | ast::ExprKind::Use(..) | ast::ExprKind::Type(..) - | ast::ExprKind::Yield(_, _) + | ast::ExprKind::Yield(..) | ast::ExprKind::Underscore => false, } } From 027423d2c460966eede3ad239b32392f2cf4de90 Mon Sep 17 00:00:00 2001 From: LuuuXXX Date: Wed, 19 Mar 2025 17:23:34 +0800 Subject: [PATCH 17/24] Fix: add ohos target notes --- src/doc/rustc/src/platform-support.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 058b0b0a07abe..e8f8684740ac0 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -89,11 +89,11 @@ target | notes -------|------- `aarch64-pc-windows-msvc` | ARM64 Windows MSVC `aarch64-unknown-linux-musl` | ARM64 Linux with musl 1.2.3 -[`aarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | ARM64 OpenHarmony +[`aarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ARM64 OpenHarmony `arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2, glibc 2.17) `arm-unknown-linux-gnueabihf` | Armv6 Linux, hardfloat (kernel 3.2, glibc 2.17) `armv7-unknown-linux-gnueabihf` | Armv7-A Linux, hardfloat (kernel 3.2, glibc 2.17) -[`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | Armv7-A OpenHarmony +[`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | Armv7-A OpenHarmony [`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36) [`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5) `powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17) @@ -106,7 +106,7 @@ target | notes [`x86_64-unknown-freebsd`](platform-support/freebsd.md) | 64-bit x86 FreeBSD [`x86_64-unknown-illumos`](platform-support/illumos.md) | illumos `x86_64-unknown-linux-musl` | 64-bit Linux with musl 1.2.3 -[`x86_64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | x86_64 OpenHarmony +[`x86_64-unknown-linux-ohos`](platform-support/openharmony.md) | x86_64 OpenHarmony [`x86_64-unknown-netbsd`](platform-support/netbsd.md) | NetBSD/amd64 ## Tier 2 without Host Tools From f27cab806e5506fe27b71211af0ee3e9fa2ffdeb Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 14 Mar 2025 09:03:23 +1100 Subject: [PATCH 18/24] Use `Option` for lowered param names. Parameter patterns are lowered to an `Ident` by `lower_fn_params_to_names`, which is used when lowering bare function types, trait methods, and foreign functions. Currently, there are two exceptional cases where the lowered param can become an empty `Ident`. - If the incoming pattern is an empty `Ident`. This occurs if the parameter is anonymous, e.g. in a bare function type. - If the incoming pattern is neither an ident nor an underscore. Any such parameter will have triggered a compile error (hence the `span_delayed_bug`), but lowering still occurs. This commit replaces these empty `Ident` results with `None`, which eliminates a number of `kw::Empty` uses, and makes it impossible to fail to check for these exceptional cases. Note: the `FIXME` comment in `is_unwrap_or_empty_symbol` is removed. It actually should have been removed in #138482, the precursor to this PR. That PR changed the lowering of wild patterns to `_` symbols instead of empty symbols, which made the mentioned underscore check load-bearing. --- compiler/rustc_ast_lowering/src/lib.rs | 14 ++++-- .../src/diagnostics/conflict_errors.rs | 12 ++--- .../rustc_borrowck/src/diagnostics/mod.rs | 2 +- compiler/rustc_hir/src/hir.rs | 13 ++++-- compiler/rustc_hir/src/intravisit.rs | 8 +++- .../src/check/compare_impl_item.rs | 8 +++- .../src/hir_ty_lowering/cmse.rs | 10 +++-- compiler/rustc_hir_pretty/src/lib.rs | 9 ++-- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 17 ++++--- .../rustc_hir_typeck/src/method/suggest.rs | 2 +- compiler/rustc_lint/src/nonstandard_style.rs | 4 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 2 +- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/hir/map.rs | 8 ++-- compiler/rustc_middle/src/query/mod.rs | 2 +- .../rustc_resolve/src/late/diagnostics.rs | 11 +++-- .../src/error_reporting/traits/suggestions.rs | 9 ++-- src/librustdoc/clean/mod.rs | 24 +++++----- .../src/functions/renamed_function_params.rs | 45 ++++++++++--------- .../clippy/clippy_lints/src/lifetimes.rs | 10 ++--- 20 files changed, 125 insertions(+), 87 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index e24b45c5b1947..e08850da4a7a8 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1513,16 +1513,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { })) } - fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] { + fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Option] { self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind { - PatKind::Ident(_, ident, _) => self.lower_ident(ident), - PatKind::Wild => Ident::new(kw::Underscore, self.lower_span(param.pat.span)), + PatKind::Ident(_, ident, _) => { + if ident.name != kw::Empty { + Some(self.lower_ident(ident)) + } else { + None + } + } + PatKind::Wild => Some(Ident::new(kw::Underscore, self.lower_span(param.pat.span))), _ => { self.dcx().span_delayed_bug( param.pat.span, "non-ident/wild param pat must trigger an error", ); - Ident::new(kw::Empty, self.lower_span(param.pat.span)) + None } })) } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 2694a1eda78d7..978186f76a1f0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2514,12 +2514,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let ty::Tuple(params) = tupled_params.kind() else { return }; // Find the first argument with a matching type, get its name - let Some((_, this_name)) = - params.iter().zip(tcx.hir_body_param_names(closure.body)).find(|(param_ty, name)| { + let Some(this_name) = params.iter().zip(tcx.hir_body_param_names(closure.body)).find_map( + |(param_ty, name)| { // FIXME: also support deref for stuff like `Rc` arguments - param_ty.peel_refs() == local_ty && name != &Ident::empty() - }) - else { + if param_ty.peel_refs() == local_ty { name } else { None } + }, + ) else { return; }; @@ -3787,7 +3787,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { method_args, *fn_span, call_source.from_hir_call(), - Some(self.infcx.tcx.fn_arg_names(method_did)[0]), + self.infcx.tcx.fn_arg_names(method_did)[0], ) { err.note(format!("borrow occurs due to deref coercion to `{deref_target_ty}`")); diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 208d510db2e1f..899e145c2c049 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1029,7 +1029,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { method_args, *fn_span, call_source.from_hir_call(), - Some(self.infcx.tcx.fn_arg_names(method_did)[0]), + self.infcx.tcx.fn_arg_names(method_did)[0], ); return FnSelfUse { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index b5857e359a2ce..751c379b21a64 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2949,7 +2949,7 @@ impl<'hir> TraitItem<'hir> { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum TraitFn<'hir> { /// No default body in the trait, just a signature. - Required(&'hir [Ident]), + Required(&'hir [Option]), /// Both signature and body are provided in the trait. Provided(BodyId), @@ -3354,7 +3354,9 @@ pub struct BareFnTy<'hir> { pub abi: ExternAbi, pub generic_params: &'hir [GenericParam<'hir>], pub decl: &'hir FnDecl<'hir>, - pub param_names: &'hir [Ident], + // `Option` because bare fn parameter names are optional. We also end up + // with `None` in some error cases, e.g. invalid parameter patterns. + pub param_names: &'hir [Option], } #[derive(Debug, Clone, Copy, HashStable_Generic)] @@ -4335,7 +4337,12 @@ impl ForeignItem<'_> { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum ForeignItemKind<'hir> { /// A foreign function. - Fn(FnSig<'hir>, &'hir [Ident], &'hir Generics<'hir>), + /// + /// All argument idents are actually always present (i.e. `Some`), but + /// `&[Option]` is used because of code paths shared with `TraitFn` + /// and `BareFnTy`. The sharing is due to all of these cases not allowing + /// arbitrary patterns for parameters. + Fn(FnSig<'hir>, &'hir [Option], &'hir Generics<'hir>), /// A foreign static item (`static ext: u8`). Static(&'hir Ty<'hir>, Mutability, Safety), /// A foreign type. diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index b79ae1e7cc21e..506358341b501 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -655,7 +655,9 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>( ForeignItemKind::Fn(ref sig, param_names, ref generics) => { try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_fn_decl(sig.decl)); - walk_list!(visitor, visit_ident, param_names.iter().copied()); + for ident in param_names.iter().copied() { + visit_opt!(visitor, visit_ident, ident); + } } ForeignItemKind::Static(ref typ, _, _) => { try_visit!(visitor.visit_ty_unambig(typ)); @@ -1169,7 +1171,9 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>( } TraitItemKind::Fn(ref sig, TraitFn::Required(param_names)) => { try_visit!(visitor.visit_fn_decl(sig.decl)); - walk_list!(visitor, visit_ident, param_names.iter().copied()); + for ident in param_names.iter().copied() { + visit_opt!(visitor, visit_ident, ident); + } } TraitItemKind::Fn(ref sig, TraitFn::Provided(body_id)) => { try_visit!(visitor.visit_fn( diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index ca820deebdfad..84d07c711fa40 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1034,7 +1034,13 @@ fn report_trait_method_mismatch<'tcx>( let span = tcx .hir_body_param_names(body) .zip(sig.decl.inputs.iter()) - .map(|(param, ty)| param.span.to(ty.span)) + .map(|(param_name, ty)| { + if let Some(param_name) = param_name { + param_name.span.to(ty.span) + } else { + ty.span + } + }) .next() .unwrap_or(impl_err_span); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index 5fed2e352879c..170500c7a1628 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -49,10 +49,12 @@ pub(crate) fn validate_cmse_abi<'tcx>( Ok(Err(index)) => { // fn(x: u32, u32, u32, u16, y: u16) -> u32, // ^^^^^^ - let span = bare_fn_ty.param_names[index] - .span - .to(bare_fn_ty.decl.inputs[index].span) - .to(bare_fn_ty.decl.inputs.last().unwrap().span); + let span = if let Some(ident) = bare_fn_ty.param_names[index] { + ident.span.to(bare_fn_ty.decl.inputs[index].span) + } else { + bare_fn_ty.decl.inputs[index].span + } + .to(bare_fn_ty.decl.inputs.last().unwrap().span); let plural = bare_fn_ty.param_names.len() - index != 1; dcx.emit_err(errors::CmseInputsStackSpill { span, plural, abi }); } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 98b81dd3def34..ddaca89ccf82d 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2,6 +2,7 @@ //! the definitions in this file have equivalents in `rustc_ast_pretty`. // tidy-alphabetical-start +#![feature(let_chains)] #![recursion_limit = "256"] // tidy-alphabetical-end @@ -898,7 +899,7 @@ impl<'a> State<'a> { ident: Ident, m: &hir::FnSig<'_>, generics: &hir::Generics<'_>, - arg_names: &[Ident], + arg_names: &[Option], body_id: Option, ) { self.print_fn(m.decl, m.header, Some(ident.name), generics, arg_names, body_id); @@ -2121,7 +2122,7 @@ impl<'a> State<'a> { header: hir::FnHeader, name: Option, generics: &hir::Generics<'_>, - arg_names: &[Ident], + arg_names: &[Option], body_id: Option, ) { self.print_fn_header_info(header); @@ -2141,7 +2142,7 @@ impl<'a> State<'a> { s.print_implicit_self(&decl.implicit_self); } else { if let Some(arg_name) = arg_names.get(i) { - if arg_name.name != kw::Empty { + if let Some(arg_name) = arg_name { s.word(arg_name.to_string()); s.word(":"); s.space(); @@ -2451,7 +2452,7 @@ impl<'a> State<'a> { decl: &hir::FnDecl<'_>, name: Option, generic_params: &[hir::GenericParam<'_>], - arg_names: &[Ident], + arg_names: &[Option], ) { self.ibox(INDENT_UNIT); self.print_formal_generic_params(generic_params); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 90bdb3c4b3739..f4bd7ec701f8a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1135,7 +1135,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && self.tcx.def_kind(fn_def_id).is_fn_like() && let self_implicit = matches!(call_expr.kind, hir::ExprKind::MethodCall(..)) as usize - && let Some(arg) = + && let Some(Some(arg)) = self.tcx.fn_arg_names(fn_def_id).get(expected_idx.as_usize() + self_implicit) && arg.name != kw::SelfLower { @@ -2678,7 +2678,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { params.get(is_method as usize..params.len() - sig.decl.c_variadic as usize)?; debug_assert_eq!(params.len(), fn_inputs.len()); Some(( - fn_inputs.zip(params.iter().map(|¶m| FnParam::Name(param))).collect(), + fn_inputs.zip(params.iter().map(|&ident| FnParam::Name(ident))).collect(), generics, )) } @@ -2709,14 +2709,20 @@ impl<'tcx> Visitor<'tcx> for FindClosureArg<'tcx> { #[derive(Clone, Copy)] enum FnParam<'hir> { Param(&'hir hir::Param<'hir>), - Name(Ident), + Name(Option), } impl FnParam<'_> { fn span(&self) -> Span { match self { Self::Param(param) => param.span, - Self::Name(ident) => ident.span, + Self::Name(ident) => { + if let Some(ident) = ident { + ident.span + } else { + DUMMY_SP + } + } } } @@ -2733,7 +2739,8 @@ impl FnParam<'_> { Some(ident.name) } FnParam::Name(ident) - if ident.name != kw::Empty && ident.name != kw::Underscore => + if let Some(ident) = ident + && ident.name != kw::Underscore => { Some(ident.name) } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index cdfae51583b60..908c3ee2eb8e3 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3766,7 +3766,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let self_first_arg = match method { hir::TraitFn::Required([ident, ..]) => { - ident.name == kw::SelfLower + matches!(ident, Some(Ident { name: kw::SelfLower, .. })) } hir::TraitFn::Provided(body_id) => { self.tcx.hir_body(*body_id).params.first().is_some_and( diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 715e3506ab824..752636ccaf061 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -424,7 +424,9 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { if let hir::TraitItemKind::Fn(_, hir::TraitFn::Required(pnames)) = item.kind { self.check_snake_case(cx, "trait method", &item.ident); for param_name in pnames { - self.check_snake_case(cx, "variable", param_name); + if let Some(param_name) = param_name { + self.check_snake_case(cx, "variable", param_name); + } } } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index e60904eebeb8b..24248e8dde34c 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1318,7 +1318,7 @@ impl<'a> CrateMetadataRef<'a> { .expect("argument names not encoded for a function") .decode((self, sess)) .nth(0) - .is_some_and(|ident| ident.name == kw::SelfLower) + .is_some_and(|ident| matches!(ident, Some(Ident { name: kw::SelfLower, .. }))) } fn get_associated_item_or_field_def_ids(self, id: DefIndex) -> impl Iterator { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 5536c93f84a43..dc453b1e747ca 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -443,7 +443,7 @@ define_tables! { rendered_const: Table>, rendered_precise_capturing_args: Table>>, asyncness: Table, - fn_arg_names: Table>, + fn_arg_names: Table>>, coroutine_kind: Table, coroutine_for_closure: Table, coroutine_by_move_body_def_id: Table, diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 2e589150d3ee6..f17efab81ec53 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -280,11 +280,11 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn hir_body_param_names(self, id: BodyId) -> impl Iterator { + pub fn hir_body_param_names(self, id: BodyId) -> impl Iterator> { self.hir_body(id).params.iter().map(|param| match param.pat.kind { - PatKind::Binding(_, _, ident, _) => ident, - PatKind::Wild => Ident::new(kw::Underscore, param.pat.span), - _ => Ident::empty(), + PatKind::Binding(_, _, ident, _) => Some(ident), + PatKind::Wild => Some(Ident::new(kw::Underscore, param.pat.span)), + _ => None, }) } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 94a5a3769a322..527c18addbe12 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1410,7 +1410,7 @@ rustc_queries! { desc { |tcx| "computing target features for inline asm of `{}`", tcx.def_path_str(def_id) } } - query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::Ident] { + query fn_arg_names(def_id: DefId) -> &'tcx [Option] { desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) } separate_provide_extern } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index bcfcc8000c718..3d666055a94fb 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2217,12 +2217,11 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { .delegation_fn_sigs .get(&def_id) .is_some_and(|sig| sig.has_self), - None => self - .r - .tcx - .fn_arg_names(def_id) - .first() - .is_some_and(|ident| ident.name == kw::SelfLower), + None => { + self.r.tcx.fn_arg_names(def_id).first().is_some_and(|&ident| { + matches!(ident, Some(Ident { name: kw::SelfLower, .. })) + }) + } }; if has_self { return Some(AssocSuggestion::MethodWithSelf { called }); diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 393d175ea4cd0..dc8022b95c313 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1992,13 +1992,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .iter() .enumerate() .map(|(i, ident)| { - if ident.name.is_empty() - || ident.name == kw::Underscore - || ident.name == kw::SelfLower + if let Some(ident) = ident + && !matches!(ident, Ident { name: kw::Underscore | kw::SelfLower, .. }) { - format!("arg{i}") - } else { format!("{ident}") + } else { + format!("arg{i}") } }) .collect(); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4ecf702d7b6ef..de6dc088176ff 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1088,7 +1088,7 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[hir::Attrib enum FunctionArgs<'tcx> { Body(hir::BodyId), - Names(&'tcx [Ident]), + Names(&'tcx [Option]), } fn clean_function<'tcx>( @@ -1117,13 +1117,15 @@ fn clean_function<'tcx>( fn clean_args_from_types_and_names<'tcx>( cx: &mut DocContext<'tcx>, types: &[hir::Ty<'tcx>], - names: &[Ident], + names: &[Option], ) -> Arguments { - fn nonempty_name(ident: &Ident) -> Option { - if ident.name == kw::Underscore || ident.name == kw::Empty { - None - } else { + fn nonempty_name(ident: &Option) -> Option { + if let Some(ident) = ident + && ident.name != kw::Underscore + { Some(ident.name) + } else { + None } } @@ -1216,11 +1218,11 @@ fn clean_poly_fn_sig<'tcx>( .iter() .map(|t| Argument { type_: clean_middle_ty(t.map_bound(|t| *t), cx, None, None), - name: names - .next() - .map(|i| i.name) - .filter(|i| !i.is_empty()) - .unwrap_or(kw::Underscore), + name: if let Some(Some(ident)) = names.next() { + ident.name + } else { + kw::Underscore + }, is_const: false, }) .collect(), diff --git a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs index 5ad83f886e2ec..041f6228fba2d 100644 --- a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs +++ b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs @@ -5,7 +5,7 @@ use rustc_hir::hir_id::OwnerId; use rustc_hir::{Impl, ImplItem, ImplItemKind, ImplItemRef, ItemKind, Node, TraitRef}; use rustc_lint::LateContext; use rustc_span::Span; -use rustc_span::symbol::{Ident, Symbol, kw}; +use rustc_span::symbol::{Ident, kw}; use super::RENAMED_FUNCTION_PARAMS; @@ -51,22 +51,33 @@ struct RenamedFnArgs(Vec<(Span, String)>); impl RenamedFnArgs { /// Comparing between an iterator of default names and one with current names, /// then collect the ones that got renamed. - fn new(default_names: &mut I, current_names: &mut T) -> Self + fn new(default_idents: &mut I1, current_idents: &mut I2) -> Self where - I: Iterator, - T: Iterator, + I1: Iterator>, + I2: Iterator>, { let mut renamed: Vec<(Span, String)> = vec![]; - debug_assert!(default_names.size_hint() == current_names.size_hint()); - while let (Some(def_name), Some(cur_name)) = (default_names.next(), current_names.next()) { - let current_name = cur_name.name; - let default_name = def_name.name; - if is_unused_or_empty_symbol(current_name) || is_unused_or_empty_symbol(default_name) { - continue; - } - if current_name != default_name { - renamed.push((cur_name.span, default_name.to_string())); + debug_assert!(default_idents.size_hint() == current_idents.size_hint()); + while let (Some(default_ident), Some(current_ident)) = + (default_idents.next(), current_idents.next()) + { + let has_name_to_check = |ident: Option| { + if let Some(ident) = ident + && ident.name != kw::Underscore + && !ident.name.as_str().starts_with('_') + { + Some(ident) + } else { + None + } + }; + + if let Some(default_ident) = has_name_to_check(default_ident) + && let Some(current_ident) = has_name_to_check(current_ident) + && default_ident.name != current_ident.name + { + renamed.push((current_ident.span, default_ident.to_string())); } } @@ -83,14 +94,6 @@ impl RenamedFnArgs { } } -fn is_unused_or_empty_symbol(symbol: Symbol) -> bool { - // FIXME: `body_param_names` currently returning empty symbols for `wild` as well, - // so we need to check if the symbol is empty first. - // Therefore the check of whether it's equal to [`kw::Underscore`] has no use for now, - // but it would be nice to keep it here just to be future-proof. - symbol.is_empty() || symbol == kw::Underscore || symbol.as_str().starts_with('_') -} - /// Get the [`trait_item_def_id`](ImplItemRef::trait_item_def_id) of a relevant impl item. fn trait_item_def_id_of_impl(items: &[ImplItemRef], target: OwnerId) -> Option { items.iter().find_map(|item| { diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 3dd2de1fafc72..8d47c756fc53c 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -189,7 +189,7 @@ fn check_fn_inner<'tcx>( cx: &LateContext<'tcx>, sig: &'tcx FnSig<'_>, body: Option, - trait_sig: Option<&[Ident]>, + trait_sig: Option<&[Option]>, generics: &'tcx Generics<'_>, span: Span, report_extra_lifetimes: bool, @@ -264,7 +264,7 @@ fn could_use_elision<'tcx>( cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, body: Option, - trait_sig: Option<&[Ident]>, + trait_sig: Option<&[Option]>, named_generics: &'tcx [GenericParam<'_>], msrv: Msrv, ) -> Option<(Vec, Vec)> { @@ -310,7 +310,7 @@ fn could_use_elision<'tcx>( let body = cx.tcx.hir_body(body_id); let first_ident = body.params.first().and_then(|param| param.pat.simple_ident()); - if non_elidable_self_type(cx, func, first_ident, msrv) { + if non_elidable_self_type(cx, func, Some(first_ident), msrv) { return None; } @@ -384,8 +384,8 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxIndexSet(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option, msrv: Msrv) -> bool { - if let Some(ident) = ident +fn non_elidable_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option>, msrv: Msrv) -> bool { + if let Some(Some(ident)) = ident && ident.name == kw::SelfLower && !func.implicit_self.has_implicit_self() && let Some(self_ty) = func.inputs.first() From 5a52b5d92aec9427b40aee6a20093eb822702402 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Wed, 19 Mar 2025 18:45:16 +0800 Subject: [PATCH 19/24] Suggest `-Whelp` when pass `--print lints` to rustc Signed-off-by: xizheyin --- compiler/rustc_session/src/config.rs | 6 ++++++ tests/ui/invalid-compile-flags/print.stderr | 1 + tests/ui/rustc-print-info-issue-138612.rs | 2 ++ tests/ui/rustc-print-info-issue-138612.stderr | 6 ++++++ 4 files changed, 15 insertions(+) create mode 100644 tests/ui/rustc-print-info-issue-138612.rs create mode 100644 tests/ui/rustc-print-info-issue-138612.stderr diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 701d06e4fd403..43b78423c727f 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2082,6 +2082,12 @@ fn emit_unknown_print_request_help(early_dcx: &EarlyDiagCtxt, req: &str) -> ! { let mut diag = early_dcx.early_struct_fatal(format!("unknown print request: `{req}`")); #[allow(rustc::diagnostic_outside_of_impl)] diag.help(format!("valid print requests are: {prints}")); + + if req == "lints" { + diag.help(format!("use `-Whelp` to print a list of lints")); + } + + diag.help(format!("for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information")); diag.emit() } diff --git a/tests/ui/invalid-compile-flags/print.stderr b/tests/ui/invalid-compile-flags/print.stderr index df0c3977dc8f6..4ea06a06539af 100644 --- a/tests/ui/invalid-compile-flags/print.stderr +++ b/tests/ui/invalid-compile-flags/print.stderr @@ -1,4 +1,5 @@ error: unknown print request: `yyyy` | = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` + = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information diff --git a/tests/ui/rustc-print-info-issue-138612.rs b/tests/ui/rustc-print-info-issue-138612.rs new file mode 100644 index 0000000000000..65b595635b158 --- /dev/null +++ b/tests/ui/rustc-print-info-issue-138612.rs @@ -0,0 +1,2 @@ +//@ check-fail +//@ compile-flags: /dev/null --print lints diff --git a/tests/ui/rustc-print-info-issue-138612.stderr b/tests/ui/rustc-print-info-issue-138612.stderr new file mode 100644 index 0000000000000..4f7ed8219521d --- /dev/null +++ b/tests/ui/rustc-print-info-issue-138612.stderr @@ -0,0 +1,6 @@ +error: unknown print request: `lints` + | + = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` + = help: use `-Whelp` to print a list of lints + = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information + From 9b88fd09d73b3808d8ff5a8cf3d68a0ca5ac1ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 19 Mar 2025 15:35:47 +0100 Subject: [PATCH 20/24] Update GCC submodule --- src/gcc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gcc b/src/gcc index 48664a6cab29d..13cc8243226a9 160000 --- a/src/gcc +++ b/src/gcc @@ -1 +1 @@ -Subproject commit 48664a6cab29d48138ffa004b7978d52ef73e3ac +Subproject commit 13cc8243226a9028bb08ab6c5e1c5fe6d533bcdf From b5069da9df85b8f374a3fd59c2145396e374537d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 19 Mar 2025 22:44:19 +0100 Subject: [PATCH 21/24] Check attrs: Don't try to retrieve the name of list stems --- compiler/rustc_passes/src/check_attr.rs | 3 +-- tests/ui/rustdoc/doc-alias-use-item-list-stem.rs | 11 +++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 tests/ui/rustdoc/doc-alias-use-item-list-stem.rs diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d1917f39c07f7..bba172ce14421 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -952,8 +952,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { tcx.dcx().emit_err(errors::DocAliasBadLocation { span, attr_str, location }); return; } - let item_name = self.tcx.hir_name(hir_id); - if item_name == doc_alias { + if self.tcx.hir_opt_name(hir_id) == Some(doc_alias) { tcx.dcx().emit_err(errors::DocAliasNotAnAlias { span, attr_str }); return; } diff --git a/tests/ui/rustdoc/doc-alias-use-item-list-stem.rs b/tests/ui/rustdoc/doc-alias-use-item-list-stem.rs new file mode 100644 index 0000000000000..ef310843e2136 --- /dev/null +++ b/tests/ui/rustdoc/doc-alias-use-item-list-stem.rs @@ -0,0 +1,11 @@ +// Check that we don't ICE on `#[doc(alias)]`es placed on use items with list stems. +// issue: +//@ check-pass + +#[doc(alias = "empty")] +pub use {}; + +#[doc(alias = "id")] +pub use {std::convert::identity}; + +fn main() {} From d07ef5b0e1f7551ad24f86256d63a5dfdb907c17 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 4 Mar 2025 21:55:43 +1100 Subject: [PATCH 22/24] coverage: Add LLVM plumbing for expansion regions This is currently unused, but paves the way for future work on expansion regions without having to worry about the FFI parts. --- .../src/coverageinfo/ffi.rs | 19 +++++++++++++++++-- .../src/coverageinfo/llvm_cov.rs | 16 ++++++++++++++-- .../src/coverageinfo/mapgen/covfun.rs | 11 ++++++++--- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 ++ .../llvm-wrapper/CoverageMappingWrapper.cpp | 16 ++++++++++++++++ 5 files changed, 57 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs index b617f4d37f5bf..f6000e7284002 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs @@ -146,6 +146,7 @@ pub(crate) struct CoverageSpan { #[derive(Clone, Debug, Default)] pub(crate) struct Regions { pub(crate) code_regions: Vec, + pub(crate) expansion_regions: Vec, pub(crate) branch_regions: Vec, pub(crate) mcdc_branch_regions: Vec, pub(crate) mcdc_decision_regions: Vec, @@ -154,10 +155,16 @@ pub(crate) struct Regions { impl Regions { /// Returns true if none of this structure's tables contain any regions. pub(crate) fn has_no_regions(&self) -> bool { - let Self { code_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions } = - self; + let Self { + code_regions, + expansion_regions, + branch_regions, + mcdc_branch_regions, + mcdc_decision_regions, + } = self; code_regions.is_empty() + && expansion_regions.is_empty() && branch_regions.is_empty() && mcdc_branch_regions.is_empty() && mcdc_decision_regions.is_empty() @@ -172,6 +179,14 @@ pub(crate) struct CodeRegion { pub(crate) counter: Counter, } +/// Must match the layout of `LLVMRustCoverageExpansionRegion`. +#[derive(Clone, Debug)] +#[repr(C)] +pub(crate) struct ExpansionRegion { + pub(crate) cov_span: CoverageSpan, + pub(crate) expanded_file_id: u32, +} + /// Must match the layout of `LLVMRustCoverageBranchRegion`. #[derive(Clone, Debug)] #[repr(C)] diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs index 2cd7fa3225acd..907d6d41a1fb5 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs @@ -63,8 +63,18 @@ pub(crate) fn write_function_mappings_to_buffer( expressions: &[ffi::CounterExpression], regions: &ffi::Regions, ) -> Vec { - let ffi::Regions { code_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions } = - regions; + let ffi::Regions { + code_regions, + expansion_regions, + branch_regions, + mcdc_branch_regions, + mcdc_decision_regions, + } = regions; + + // SAFETY: + // - All types are FFI-compatible and have matching representations in Rust/C++. + // - For pointer/length pairs, the pointer and length come from the same vector or slice. + // - C++ code does not retain any pointers after the call returns. llvm::build_byte_buffer(|buffer| unsafe { llvm::LLVMRustCoverageWriteFunctionMappingsToBuffer( virtual_file_mapping.as_ptr(), @@ -73,6 +83,8 @@ pub(crate) fn write_function_mappings_to_buffer( expressions.len(), code_regions.as_ptr(), code_regions.len(), + expansion_regions.as_ptr(), + expansion_regions.len(), branch_regions.as_ptr(), branch_regions.len(), mcdc_branch_regions.as_ptr(), diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs index 5b487bc1a8bde..b8082edb9d532 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs @@ -120,13 +120,18 @@ fn fill_region_tables<'tcx>( // Associate that global file ID with a local file ID for this function. let local_file_id = covfun.virtual_file_mapping.local_id_for_global(global_file_id); - let ffi::Regions { code_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions } = - &mut covfun.regions; - let make_cov_span = |span: Span| spans::make_coverage_span(local_file_id, source_map, &source_file, span); let discard_all = tcx.sess.coverage_discard_all_spans_in_codegen(); + let ffi::Regions { + code_regions, + expansion_regions: _, // FIXME(Zalathar): Fill out support for expansion regions + branch_regions, + mcdc_branch_regions, + mcdc_decision_regions, + } = &mut covfun.regions; + // For each counter/region pair in this function+file, convert it to a // form suitable for FFI. for &Mapping { ref kind, span } in &fn_cov_info.mappings { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 39087a4d6f41d..83efb3ea66039 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2019,6 +2019,8 @@ unsafe extern "C" { NumExpressions: size_t, CodeRegions: *const crate::coverageinfo::ffi::CodeRegion, NumCodeRegions: size_t, + ExpansionRegions: *const crate::coverageinfo::ffi::ExpansionRegion, + NumExpansionRegions: size_t, BranchRegions: *const crate::coverageinfo::ffi::BranchRegion, NumBranchRegions: size_t, MCDCBranchRegions: *const crate::coverageinfo::ffi::MCDCBranchRegion, diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp index 0471baa1f9cad..b8884486c3330 100644 --- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp @@ -77,6 +77,13 @@ struct LLVMRustCoverageCodeRegion { LLVMRustCounter Count; }; +// Must match the layout of +// `rustc_codegen_llvm::coverageinfo::ffi::ExpansionRegion`. +struct LLVMRustCoverageExpansionRegion { + LLVMRustCoverageSpan Span; + uint32_t ExpandedFileID; +}; + // Must match the layout of // `rustc_codegen_llvm::coverageinfo::ffi::BranchRegion`. struct LLVMRustCoverageBranchRegion { @@ -151,6 +158,8 @@ extern "C" void LLVMRustCoverageWriteFunctionMappingsToBuffer( const unsigned *VirtualFileMappingIDs, size_t NumVirtualFileMappingIDs, const LLVMRustCounterExpression *RustExpressions, size_t NumExpressions, const LLVMRustCoverageCodeRegion *CodeRegions, size_t NumCodeRegions, + const LLVMRustCoverageExpansionRegion *ExpansionRegions, + size_t NumExpansionRegions, const LLVMRustCoverageBranchRegion *BranchRegions, size_t NumBranchRegions, const LLVMRustCoverageMCDCBranchRegion *MCDCBranchRegions, size_t NumMCDCBranchRegions, @@ -179,6 +188,13 @@ extern "C" void LLVMRustCoverageWriteFunctionMappingsToBuffer( Region.Span.ColumnStart, Region.Span.LineEnd, Region.Span.ColumnEnd)); } + // Expansion regions: + for (const auto &Region : ArrayRef(ExpansionRegions, NumExpansionRegions)) { + MappingRegions.push_back(coverage::CounterMappingRegion::makeExpansion( + Region.Span.FileID, Region.ExpandedFileID, Region.Span.LineStart, + Region.Span.ColumnStart, Region.Span.LineEnd, Region.Span.ColumnEnd)); + } + // Branch regions: for (const auto &Region : ArrayRef(BranchRegions, NumBranchRegions)) { MappingRegions.push_back(coverage::CounterMappingRegion::makeBranchRegion( From 2e36990881e25986ca5dc08b74d79b9a527b4404 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 20 Mar 2025 12:26:28 +1100 Subject: [PATCH 23/24] coverage: Convert and check span coordinates without a local file ID For expansion region support, we will want to be able to convert and check spans before creating a corresponding local file ID. If we create local file IDs eagerly, but some expansion turns out to have no successfully-converted spans, LLVM will complain about that expansion's file ID having no regions. --- .../src/coverageinfo/mapgen/covfun.rs | 22 ++++----- .../src/coverageinfo/mapgen/spans.rs | 45 +++++++++++++------ 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs index b8082edb9d532..048e1988c3278 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs @@ -120,9 +120,14 @@ fn fill_region_tables<'tcx>( // Associate that global file ID with a local file ID for this function. let local_file_id = covfun.virtual_file_mapping.local_id_for_global(global_file_id); - let make_cov_span = - |span: Span| spans::make_coverage_span(local_file_id, source_map, &source_file, span); + // In rare cases, _all_ of a function's spans are discarded, and coverage + // codegen needs to handle that gracefully to avoid #133606. + // It's hard for tests to trigger this organically, so instead we set + // `-Zcoverage-options=discard-all-spans-in-codegen` to force it to occur. let discard_all = tcx.sess.coverage_discard_all_spans_in_codegen(); + let make_coords = |span: Span| { + if discard_all { None } else { spans::make_coords(source_map, &source_file, span) } + }; let ffi::Regions { code_regions, @@ -145,17 +150,8 @@ fn fill_region_tables<'tcx>( ffi::Counter::from_term(term) }; - // Convert the `Span` into coordinates that we can pass to LLVM, or - // discard the span if conversion fails. In rare, cases _all_ of a - // function's spans are discarded, and the rest of coverage codegen - // needs to handle that gracefully to avoid a repeat of #133606. - // We don't have a good test case for triggering that organically, so - // instead we set `-Zcoverage-options=discard-all-spans-in-codegen` - // to force it to occur. - let Some(cov_span) = make_cov_span(span) else { continue }; - if discard_all { - continue; - } + let Some(coords) = make_coords(span) else { continue }; + let cov_span = coords.make_coverage_span(local_file_id); match *kind { MappingKind::Code { bcb } => { diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs index 3193be31ada9f..39a59560c9d3e 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/spans.rs @@ -5,22 +5,40 @@ use tracing::debug; use crate::coverageinfo::ffi; use crate::coverageinfo::mapgen::LocalFileId; +/// Line and byte-column coordinates of a source code span within some file. +/// The file itself must be tracked separately. +#[derive(Clone, Copy, Debug)] +pub(crate) struct Coords { + /// 1-based starting line of the source code span. + pub(crate) start_line: u32, + /// 1-based starting column (in bytes) of the source code span. + pub(crate) start_col: u32, + /// 1-based ending line of the source code span. + pub(crate) end_line: u32, + /// 1-based ending column (in bytes) of the source code span. High bit must be unset. + pub(crate) end_col: u32, +} + +impl Coords { + /// Attaches a local file ID to these coordinates to produce an `ffi::CoverageSpan`. + pub(crate) fn make_coverage_span(&self, local_file_id: LocalFileId) -> ffi::CoverageSpan { + let &Self { start_line, start_col, end_line, end_col } = self; + let file_id = local_file_id.as_u32(); + ffi::CoverageSpan { file_id, start_line, start_col, end_line, end_col } + } +} + /// Converts the span into its start line and column, and end line and column. /// /// Line numbers and column numbers are 1-based. Unlike most column numbers emitted by /// the compiler, these column numbers are denoted in **bytes**, because that's what /// LLVM's `llvm-cov` tool expects to see in coverage maps. /// -/// Returns `None` if the conversion failed for some reason. This shouldn't happen, +/// Returns `None` if the conversion failed for some reason. This should be uncommon, /// but it's hard to rule out entirely (especially in the presence of complex macros /// or other expansions), and if it does happen then skipping a span or function is /// better than an ICE or `llvm-cov` failure that the user might have no way to avoid. -pub(crate) fn make_coverage_span( - file_id: LocalFileId, - source_map: &SourceMap, - file: &SourceFile, - span: Span, -) -> Option { +pub(crate) fn make_coords(source_map: &SourceMap, file: &SourceFile, span: Span) -> Option { let span = ensure_non_empty_span(source_map, span)?; let lo = span.lo(); @@ -44,8 +62,7 @@ pub(crate) fn make_coverage_span( start_line = source_map.doctest_offset_line(&file.name, start_line); end_line = source_map.doctest_offset_line(&file.name, end_line); - check_coverage_span(ffi::CoverageSpan { - file_id: file_id.as_u32(), + check_coords(Coords { start_line: start_line as u32, start_col: start_col as u32, end_line: end_line as u32, @@ -80,8 +97,8 @@ fn ensure_non_empty_span(source_map: &SourceMap, span: Span) -> Option { /// it will immediately exit with a fatal error. To prevent that from happening, /// discard regions that are improperly ordered, or might be interpreted in a /// way that makes them improperly ordered. -fn check_coverage_span(cov_span: ffi::CoverageSpan) -> Option { - let ffi::CoverageSpan { file_id: _, start_line, start_col, end_line, end_col } = cov_span; +fn check_coords(coords: Coords) -> Option { + let Coords { start_line, start_col, end_line, end_col } = coords; // Line/column coordinates are supposed to be 1-based. If we ever emit // coordinates of 0, `llvm-cov` might misinterpret them. @@ -94,17 +111,17 @@ fn check_coverage_span(cov_span: ffi::CoverageSpan) -> Option let is_ordered = (start_line, start_col) <= (end_line, end_col); if all_nonzero && end_col_has_high_bit_unset && is_ordered { - Some(cov_span) + Some(coords) } else { debug!( - ?cov_span, + ?coords, ?all_nonzero, ?end_col_has_high_bit_unset, ?is_ordered, "Skipping source region that would be misinterpreted or rejected by LLVM" ); // If this happens in a debug build, ICE to make it easier to notice. - debug_assert!(false, "Improper source region: {cov_span:?}"); + debug_assert!(false, "Improper source region: {coords:?}"); None } } From e6004ccb50880f9667015eea2f3d90f30517abd1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 20 Mar 2025 03:21:58 +0000 Subject: [PATCH 24/24] Use def_path_str for def id arg in UnsupportedOpInfo --- compiler/rustc_const_eval/messages.ftl | 4 ++-- compiler/rustc_const_eval/src/errors.rs | 7 ++++--- tests/ui/consts/miri_unleashed/extern-static.stderr | 4 ++-- tests/ui/consts/miri_unleashed/tls.stderr | 4 ++-- tests/ui/extern/issue-28324.stderr | 2 +- tests/ui/statics/issue-14227.stderr | 2 +- 6 files changed, 12 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index ccf9b240d4088..dd481e04abbdc 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -93,7 +93,7 @@ const_eval_expected_inbounds_pointer = } const_eval_extern_static = - cannot access extern static ({$did}) + cannot access extern static `{$did}` const_eval_extern_type_field = `extern type` field does not have a known offset const_eval_fn_ptr_call = @@ -381,7 +381,7 @@ const_eval_thread_local_access = thread-local statics cannot be accessed at compile-time const_eval_thread_local_static = - cannot access thread local static ({$did}) + cannot access thread local static `{$did}` const_eval_too_generic = encountered overly generic constant const_eval_too_many_caller_args = diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index b020eeccf717f..e2675e2f4c900 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -898,6 +898,7 @@ impl ReportErrorExt for UnsupportedOpInfo { UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static, } } + fn add_args(self, diag: &mut Diag<'_, G>) { use UnsupportedOpInfo::*; @@ -917,9 +918,9 @@ impl ReportErrorExt for UnsupportedOpInfo { OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => { diag.arg("ptr", ptr); } - ThreadLocalStatic(did) | ExternStatic(did) => { - diag.arg("did", format!("{did:?}")); - } + ThreadLocalStatic(did) | ExternStatic(did) => rustc_middle::ty::tls::with(|tcx| { + diag.arg("did", tcx.def_path_str(did)); + }), } } } diff --git a/tests/ui/consts/miri_unleashed/extern-static.stderr b/tests/ui/consts/miri_unleashed/extern-static.stderr index 0979a5e4fb197..4dbabbe44a2bb 100644 --- a/tests/ui/consts/miri_unleashed/extern-static.stderr +++ b/tests/ui/consts/miri_unleashed/extern-static.stderr @@ -2,13 +2,13 @@ error[E0080]: could not evaluate static initializer --> $DIR/extern-static.rs:11:25 | LL | unsafe { let _val = DATA; } - | ^^^^ cannot access extern static (DefId(0:4 ~ extern_static[c41e]::{extern#0}::DATA)) + | ^^^^ cannot access extern static `DATA` error[E0080]: could not evaluate static initializer --> $DIR/extern-static.rs:16:14 | LL | unsafe { DATA = 0; } - | ^^^^^^^^ cannot access extern static (DefId(0:4 ~ extern_static[c41e]::{extern#0}::DATA)) + | ^^^^^^^^ cannot access extern static `DATA` error: aborting due to 2 previous errors diff --git a/tests/ui/consts/miri_unleashed/tls.stderr b/tests/ui/consts/miri_unleashed/tls.stderr index a00b7eb13128c..ef83654430318 100644 --- a/tests/ui/consts/miri_unleashed/tls.stderr +++ b/tests/ui/consts/miri_unleashed/tls.stderr @@ -2,13 +2,13 @@ error[E0080]: could not evaluate static initializer --> $DIR/tls.rs:11:25 | LL | unsafe { let _val = A; } - | ^ cannot access thread local static (DefId(0:4 ~ tls[ca29]::A)) + | ^ cannot access thread local static `A` error[E0080]: could not evaluate static initializer --> $DIR/tls.rs:20:26 | LL | unsafe { let _val = &A; } - | ^ cannot access thread local static (DefId(0:4 ~ tls[ca29]::A)) + | ^ cannot access thread local static `A` warning: skipping const checks | diff --git a/tests/ui/extern/issue-28324.stderr b/tests/ui/extern/issue-28324.stderr index 1fccb34fdf37b..93eb6ff8174e9 100644 --- a/tests/ui/extern/issue-28324.stderr +++ b/tests/ui/extern/issue-28324.stderr @@ -2,7 +2,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/issue-28324.rs:5:23 | LL | pub static BAZ: u32 = *&error_message_count; - | ^^^^^^^^^^^^^^^^^^^^^ cannot access extern static (DefId(0:4 ~ issue_28324[8ec4]::{extern#0}::error_message_count)) + | ^^^^^^^^^^^^^^^^^^^^^ cannot access extern static `error_message_count` error[E0133]: use of extern static is unsafe and requires unsafe function or block --> $DIR/issue-28324.rs:5:25 diff --git a/tests/ui/statics/issue-14227.stderr b/tests/ui/statics/issue-14227.stderr index 0aeb973bff301..3551821a3dadb 100644 --- a/tests/ui/statics/issue-14227.stderr +++ b/tests/ui/statics/issue-14227.stderr @@ -2,7 +2,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/issue-14227.rs:4:21 | LL | static CRASH: u32 = symbol; - | ^^^^^^ cannot access extern static (DefId(0:4 ~ issue_14227[1133]::{extern#0}::symbol)) + | ^^^^^^ cannot access extern static `symbol` error[E0133]: use of extern static is unsafe and requires unsafe function or block --> $DIR/issue-14227.rs:4:21